Skip to content

Commit ec7f813

Browse files
committed
detect storybook, code-gen and index-html configurability
1 parent 5f5cae9 commit ec7f813

File tree

20 files changed

+751
-69
lines changed

20 files changed

+751
-69
lines changed

npm/react/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
},
2222
"dependencies": {
2323
"@cypress/mount-utils": "0.0.0-development",
24+
"@storybook/testing-react": "0.0.22",
2425
"debug": "4.3.2",
2526
"find-webpack": "2.2.1",
2627
"find-yarn-workspace-root": "2.0.0"

npm/react/plugins/react-scripts/index.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ const { getLegacyDevServer } = require('../utils/legacy-setup-dev-server')
44

55
function devServer (cypressDevServerConfig, {
66
webpackConfigPath,
7-
} = {
8-
webpackConfigPath: 'react-scripts/config/webpack.config',
9-
}) {
7+
template,
8+
} = {}) {
109
return startDevServer({
1110
options: cypressDevServerConfig,
1211
webpackConfig: findReactScriptsWebpackConfig(cypressDevServerConfig.config, {
13-
webpackConfigPath,
12+
webpackConfigPath: webpackConfigPath || 'react-scripts/config/webpack.config',
1413
}),
14+
template,
1515
})
1616
}
1717

npm/react/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
export * from './mount'
22

33
export * from './mountHook'
4+
5+
// TODO: Create our own version and eliminate this dependency?
6+
export * from '@storybook/testing-react'

npm/vue/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"@intlify/vue-i18n-loader": "2.0.0-rc.1",
2929
"@rollup/plugin-commonjs": "^17.1.0",
3030
"@rollup/plugin-node-resolve": "^11.1.1",
31+
"@storybook/testing-vue3": "^0.0.1",
3132
"@vue/cli-plugin-babel": "~4.4.0",
3233
"@vue/cli-service": "~4.4.0",
3334
"@vue/compiler-sfc": "3.2.6",

npm/vue/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
setupHooks,
1313
} from '@cypress/mount-utils'
1414

15+
export * from '@storybook/testing-vue3'
16+
1517
const DEFAULT_COMP_NAME = 'unknown'
1618

1719
type GlobalMountOptions = Required<MountingOptions<any>>['global']

packages/app/src/navigation/SidebarNavigation.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ import SettingsIcon from '~icons/cy/settings_x24'
3434
const navigation = [
3535
{ name: 'Specs', icon: SpecsIcon, href: '/' },
3636
{ name: 'Runs', icon: CodeIcon, href: '/runs' },
37-
{ name: 'Settings', icon: SettingsIcon, href: '/settings' }
37+
{ name: 'Settings', icon: SettingsIcon, href: '/settings' },
38+
{ name: 'New Spec', icon: SettingsIcon, href: '/newspec' }
3839
]
3940
4041
defineProps<{

packages/app/src/pages/NewSpec.vue

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<template>
2+
<div v-if="query.data.value?.wizard.storybook?.configured">
3+
<h2>New Spec</h2>
4+
<ul v-if="query.data.value?.wizard?.storybook?.mainJs?.stories">
5+
<li v-for="story of query.data.value?.wizard.storybook.mainJs.stories" @click="storyClick(story)">{{story}}</li>
6+
</ul>
7+
</div>
8+
<div v-else>
9+
Storybook is not configured for this project
10+
</div>
11+
</template>
12+
13+
<route>
14+
{
15+
name: "New Spec Page"
16+
}
17+
</route>
18+
19+
<script lang="ts" setup>
20+
import { gql, useMutation, useQuery } from '@urql/vue'
21+
import { MainQueryDocument, GenerateSpecFromStoryDocument } from '../generated/graphql'
22+
23+
gql`
24+
query MainQuery {
25+
wizard {
26+
storybook {
27+
configured
28+
mainJs {
29+
stories
30+
}
31+
}
32+
}
33+
}
34+
`
35+
36+
gql`
37+
mutation GenerateSpecFromStory($storyPath: String!) {
38+
generateSpecFromStory (storyPath: $storyPath) {
39+
storybook {
40+
generatedSpecs {
41+
name,
42+
relative,
43+
absolute
44+
}
45+
}
46+
}
47+
}
48+
`
49+
50+
const query = useQuery({query: MainQueryDocument})
51+
const mutation = useMutation(GenerateSpecFromStoryDocument)
52+
53+
async function storyClick(story) {
54+
await mutation.executeMutation({storyPath: story})
55+
const generatedSpecs = mutation.data.value?.generateSpecFromStory.storybook?.generatedSpecs || []
56+
const newSpec = generatedSpecs[generatedSpecs.length - 1];
57+
// Runner doesn't pick up new file without timeout, I'm guessing a race condition between file watcher and runner starting
58+
setTimeout(() => {
59+
window.location.href = `${window.location.origin}/__/#/tests/component/${newSpec.relative}`
60+
}, 500)
61+
}
62+
</script>

packages/graphql/schemas/schema.graphql

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,15 @@ type Mutation {
250250
"""Add project to projects array and cache it"""
251251
addProject(path: String!): App!
252252

253+
"""Create an index.html for component testing."""
254+
appCreateComponentTemplate(template: String!): App
255+
253256
"""Create a Cypress config file for a new project"""
254257
appCreateConfigFile(code: String!, configFilename: String!): App
255258

259+
"""Generate spec from Storybook story"""
260+
generateSpecFromStory(framework: String, storyPath: String!): Wizard!
261+
256262
"""
257263
Initializes open_project global singleton to manager current project state
258264
"""
@@ -514,6 +520,48 @@ enum ResolvedType {
514520
string
515521
}
516522

523+
"""Storybook detection"""
524+
type Storybook {
525+
"""Whether Storybook is configured"""
526+
configured: Boolean!
527+
528+
"""Generated specs"""
529+
generatedSpecs: [StorybookFile!]!
530+
531+
"""Detected Storybook main.js file"""
532+
mainJs: StorybookMainJs
533+
534+
"""Detected Storybook preview-body.html file"""
535+
previewBody: StorybookHtmlFile
536+
537+
"""Detected Storybook preview-head.html file"""
538+
previewHead: StorybookHtmlFile
539+
540+
"""Detected Storybook preview.js file"""
541+
previewJs: StorybookFile
542+
}
543+
544+
type StorybookFile {
545+
absolute: String!
546+
name: String!
547+
relative: String!
548+
}
549+
550+
type StorybookHtmlFile {
551+
absolute: String!
552+
content: String!
553+
name: String!
554+
relative: String!
555+
}
556+
557+
type StorybookMainJs {
558+
absolute: String!
559+
name: String!
560+
relative: String!
561+
stories: [JSON]
562+
storyGlobs: [String]
563+
}
564+
517565
"""The bundlers that we can use with Cypress"""
518566
enum SupportedBundlers {
519567
vite
@@ -564,8 +612,14 @@ type Wizard {
564612

565613
"""Configuration file based on bundler and framework of choice"""
566614
sampleCode(lang: WizardCodeLanguage! = js): String
615+
616+
"""Sample index.html template code"""
617+
sampleTemplate: String
567618
step: WizardStep!
568619

620+
"""Foo"""
621+
storybook: Storybook
622+
569623
"""
570624
The testing type we are setting in the wizard, null if this has not been chosen
571625
"""

packages/graphql/src/actions/BaseActions.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { BaseContext } from '../context/BaseContext'
22
import type { FoundBrowser, OpenProjectLaunchOptions, LaunchOpts, LaunchArgs, FullConfig } from '@packages/types'
33
import type { BrowserContract } from '../contracts/BrowserContract'
44
import type { Project } from '../entities/Project'
5+
import type { Storybook } from '../entities/Storybook'
56

67
/**
78
* Acts as the contract for all actions, inherited by:
@@ -17,6 +18,7 @@ export abstract class BaseActions {
1718
abstract installDependencies (): void
1819

1920
abstract createConfigFile (code: string, configFilename: string): void
21+
abstract createComponentTemplate(template: string): void
2022

2123
abstract loadProjects (): Promise<Project[]>
2224
abstract addProject (projectRoot: string): Project
@@ -36,4 +38,8 @@ export abstract class BaseActions {
3638
abstract resolveOpenProjectConfig (): FullConfig | null
3739

3840
abstract isFirstTime (projectRoot: string, testingType: Cypress.TestingType): boolean
41+
42+
abstract detectStorybook (projectRoot: string): Promise<Storybook>
43+
44+
abstract generateSpecFromStory(storyPath: string, projectRoot: string): Promise<Cypress.Cypress['spec'] | null>
3945
}

0 commit comments

Comments
 (0)