-
-
Notifications
You must be signed in to change notification settings - Fork 9.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Angular and Vue storyshots #2564
Merged
Merged
Changes from 65 commits
Commits
Show all changes
75 commits
Select commit
Hold shift + click to select a range
97c2b42
Initial dirty-half-working-POC of the storyshots for angular
igor-dv edb1cf6
Refactor storyshots index.js
igor-dv c208016
Refactor test-bodies
igor-dv e0bae92
Better copy-past from app/angular
igor-dv 91f17b6
Remove things
igor-dv 8f549fa
Merge remote-tracking branch 'origin/master' into angular-storyshots
igor-dv 714b694
Merge remote-tracking branch 'origin/master' into angular-storyshots
igor-dv 43a273b
Merge branch 'master' into angular-storyshots
igor-dv d9942cf
Fix indentation in package.json
igor-dv 2c460e4
Extract more stories to separate files
igor-dv 887182f
Support promises in storyshots
igor-dv 9cffe0a
Allow loading html templates
igor-dv 29e84bd
Update snapshots
igor-dv f9e83ca
Merge branch 'master' into angular-storyshots
igor-dv b09b631
Few cleanups
igor-dv 3c782a6
Merge branch 'master' into angular-storyshots
igor-dv 3802a8e
Merge branch 'master' into angular-storyshots
ndelangen 3cbd772
Add vue storyshots fork
igor-dv db89374
Extract common config-loading logic to a separate module
igor-dv 7193eee
Merge remote-tracking branch 'origin/angular-storyshots' into vue-sto…
igor-dv 36daf9c
Use config-loader in vue/loader
igor-dv 5ba2e9e
Use prepare script in storyshots
igor-dv 84237fb
Angular + Jest + Storyshots = Crazy Shit. Move the `jest-preset-angul…
igor-dv 4b612eb
Merge remote-tracking branch 'origin/angular-storyshots' into vue-sto…
igor-dv 796deb5
Merge branch 'master' into angular-storyshots
igor-dv 7fc4888
Define global.STORYBOOK_ENV to be 'vue' because there are addons that…
igor-dv 08cbbc8
Move angular and react to regular reps
igor-dv 51b91d8
Merge remote-tracking branch 'origin/angular-storyshots' into vue-sto…
igor-dv 347bdc2
Add utils.test.js
igor-dv 637a919
Fix indentation
igor-dv a0d4e10
Merge pull request #2614 from storybooks/vue-storyshots
ndelangen ea2db19
Wrap story with app.component like in the app/angular and set dynamic…
igor-dv a1fd3cf
typo and indentation
igor-dv 6a5b3b8
Merge branch 'master' into angular-storyshots
igor-dv c35d48b
Update yarn.lock
igor-dv 3bb8ab9
Move angular back to peer to check if cli tests are failing.
igor-dv 45c7f24
Remove angular and vue deps from storyshots and suppress no-extraneou…
igor-dv ee1fad4
Remove react from deps as well and remove wildcard from react-test-re…
igor-dv a7a6324
Merge branch 'master' into angular-storyshots
igor-dv 3aa07d0
Update yarn.lock
igor-dv 279090c
Disable each specific import separately with ugly "eslint-disable-nex…
igor-dv 7730d21
Merge remote-tracking branch 'origin/master' into angular-storyshots
igor-dv acfd41e
Disable with specific rule, so the imports will be even uglier
igor-dv 23b85f0
Merge branch 'master' into angular-storyshots
igor-dv c4b7ecf
Merge branch 'master' into angular-storyshots
igor-dv 6115fe1
Merge branch 'master' into angular-storyshots
igor-dv 0b57690
Merge branch 'master' into angular-storyshots
igor-dv de37c4b
Merge branch 'master' into angular-storyshots
ndelangen 08ec56b
Merge branch 'master' into angular-storyshots
igor-dv e304771
Add docs for angular and vue
igor-dv 227aaf5
Merge branch 'master' into angular-storyshots
igor-dv 8eee1c0
Now I need to update snapshots...
igor-dv 2aac993
Merge remote-tracking branch 'origin/master' into angular-storyshots
igor-dv 11687bd
After merge fixes
igor-dv b0f4064
Update snapshots
igor-dv ea9adf3
Merge branch 'master' into angular-storyshots
igor-dv c3b5aa7
Merge remote-tracking branch 'origin/master' into angular-storyshots
igor-dv 805f73e
Update snapshots
igor-dv 2e30203
Merge remote-tracking branch 'origin/master' into angular-storyshots
igor-dv a5eb21c
Update storyshots to use helpers with templates support
igor-dv 9ba4b74
Generalize api. import react-test-renderer only in react loader
igor-dv 64506b4
Remove jest-preset-angular and react-test-renderer from deps.
igor-dv cb3029e
Merge branch 'master' into angular-storyshots
igor-dv 2ca902a
Merge branch 'master' into angular-storyshots
igor-dv c2ced8d
Update README
igor-dv 9091f4a
Add deps issue description to README
igor-dv d17f61b
Fix docs
igor-dv f68a410
Merge remote-tracking branch 'origin/master' into angular-storyshots
igor-dv d5b30aa
Merge remote-tracking branch 'origin/master' into angular-storyshots
igor-dv 5fcf200
Merge remote-tracking branch 'origin/master' into angular-storyshots
igor-dv 878aa75
Merge branch 'master' into angular-storyshots
igor-dv 53b9a3a
Fix image snapshot to err on RN
igor-dv 89af8fe
Merge branch 'master' into angular-storyshots
igor-dv db75151
Merge branch 'master' into angular-storyshots
igor-dv 760d3c7
Merge remote-tracking branch 'origin/master' into angular-storyshots
igor-dv File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,6 @@ root = true | |
[*] | ||
end_of_line = lf | ||
|
||
[*.{js,json,ts}] | ||
[*.{js,json,ts,vue}] | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// We could use NgComponentOutlet here but there's currently no easy way | ||
// to provide @Inputs and subscribe to @Outputs, see | ||
// https://github.com/angular/angular/issues/15360 | ||
// For the time being, the ViewContainerRef approach works pretty well. | ||
import { | ||
Component, | ||
Inject, | ||
OnInit, | ||
ViewChild, | ||
ViewContainerRef, | ||
ComponentFactoryResolver, | ||
OnDestroy, | ||
EventEmitter, | ||
SimpleChanges, | ||
SimpleChange, | ||
} from '@angular/core'; | ||
import { STORY } from './app.token'; | ||
import { NgStory, ICollection } from './types'; | ||
|
||
@Component({ | ||
selector: 'storybook-dynamic-app-root', | ||
template: '<ng-template #target></ng-template>', | ||
}) | ||
export class AppComponent implements OnInit, OnDestroy { | ||
@ViewChild('target', { read: ViewContainerRef }) | ||
target: ViewContainerRef; | ||
constructor(private cfr: ComponentFactoryResolver, @Inject(STORY) private data: NgStory) {} | ||
|
||
ngOnInit(): void { | ||
this.putInMyHtml(); | ||
} | ||
|
||
ngOnDestroy(): void { | ||
this.target.clear(); | ||
} | ||
|
||
private putInMyHtml(): void { | ||
this.target.clear(); | ||
const compFactory = this.cfr.resolveComponentFactory(this.data.component); | ||
const instance = this.target.createComponent(compFactory).instance; | ||
|
||
this.setProps(instance, this.data); | ||
} | ||
|
||
/** | ||
* Set inputs and outputs | ||
*/ | ||
private setProps(instance: any, { props = {} }: NgStory): void { | ||
const changes: SimpleChanges = {}; | ||
const hasNgOnChangesHook = !!instance['ngOnChanges']; | ||
|
||
Object.keys(props).map((key: string) => { | ||
const value = props[key]; | ||
const instanceProperty = instance[key]; | ||
|
||
if (!(instanceProperty instanceof EventEmitter) && !!value) { | ||
instance[key] = value; | ||
if (hasNgOnChangesHook) { | ||
changes[key] = new SimpleChange(undefined, value, instanceProperty === undefined); | ||
} | ||
} else if (typeof value === 'function' && key !== 'ngModelChange') { | ||
instanceProperty.subscribe(value); | ||
} | ||
}); | ||
|
||
this.callNgOnChangesHook(instance, changes); | ||
this.setNgModel(instance, props); | ||
} | ||
|
||
/** | ||
* Manually call 'ngOnChanges' hook because angular doesn't do that for dynamic components | ||
* Issue: [https://github.com/angular/angular/issues/8903] | ||
*/ | ||
private callNgOnChangesHook(instance: any, changes: SimpleChanges): void { | ||
if (!!Object.keys(changes).length) { | ||
instance.ngOnChanges(changes); | ||
} | ||
} | ||
|
||
/** | ||
* If component implements ControlValueAccessor interface try to set ngModel | ||
*/ | ||
private setNgModel(instance: any, props: ICollection): void { | ||
if (!!props['ngModel']) { | ||
instance.writeValue(props.ngModel); | ||
} | ||
|
||
if (typeof props.ngModelChange === 'function') { | ||
instance.registerOnChange(props.ngModelChange); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { InjectionToken } from '@angular/core'; | ||
import { NgStory } from './types'; | ||
|
||
export const STORY = new InjectionToken<NgStory>('story'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { Component, Type } from '@angular/core'; | ||
import { FormsModule } from '@angular/forms'; | ||
import { BrowserModule } from '@angular/platform-browser'; | ||
import { AppComponent } from './app.component'; | ||
import { STORY } from './app.token'; | ||
import { NgStory } from './types'; | ||
|
||
const getModuleMeta = ( | ||
declarations: Array<Type<any> | any[]>, | ||
entryComponents: Array<Type<any> | any[]>, | ||
bootstrap: Array<Type<any> | any[]>, | ||
data: NgStory, | ||
moduleMetadata: any | ||
) => { | ||
return { | ||
declarations: [...declarations, ...(moduleMetadata.declarations || [])], | ||
imports: [BrowserModule, FormsModule, ...(moduleMetadata.imports || [])], | ||
providers: [ | ||
{ provide: STORY, useValue: Object.assign({}, data) }, | ||
...(moduleMetadata.providers || []), | ||
], | ||
entryComponents: [...entryComponents, ...(moduleMetadata.entryComponents || [])], | ||
schemas: [...(moduleMetadata.schemas || [])], | ||
bootstrap: [...bootstrap], | ||
}; | ||
}; | ||
|
||
const createComponentFromTemplate = (template: string): Function => { | ||
const componentClass = class DynamicComponent {}; | ||
|
||
return Component({ | ||
template: template, | ||
})(componentClass); | ||
}; | ||
|
||
export const initModuleData = (storyObj: NgStory): any => { | ||
const { component, template, props, moduleMetadata = {} } = storyObj; | ||
|
||
let AnnotatedComponent; | ||
|
||
if (template) { | ||
AnnotatedComponent = createComponentFromTemplate(template); | ||
} else { | ||
AnnotatedComponent = component; | ||
} | ||
|
||
const story = { | ||
component: AnnotatedComponent, | ||
props, | ||
}; | ||
|
||
const moduleMeta = getModuleMeta( | ||
[AppComponent, AnnotatedComponent], | ||
[AnnotatedComponent], | ||
[AppComponent], | ||
story, | ||
moduleMetadata | ||
); | ||
|
||
return { | ||
AppComponent, | ||
moduleMeta, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import runWithRequireContext from '../require_context'; | ||
import hasDependency from '../hasDependency'; | ||
import loadConfig from '../config-loader'; | ||
|
||
function setupAngularJestPreset() { | ||
// Angular + Jest + Storyshots = Crazy Shit: | ||
// We need to require 'jest-preset-angular/setupJest' before any storybook code | ||
// is running inside jest - one of the things that `jest-preset-angular/setupJest` does is | ||
// extending the `window.Reflect` with all the needed metadata functions, that are required | ||
// for emission of the TS decorations like 'design:paramtypes' | ||
require.requireActual('jest-preset-angular/setupJest'); | ||
} | ||
|
||
function test(options) { | ||
return ( | ||
options.framework === 'angular' || (!options.framework && hasDependency('@storybook/angular')) | ||
); | ||
} | ||
|
||
function load(options) { | ||
setupAngularJestPreset(); | ||
|
||
const { content, contextOpts } = loadConfig({ | ||
configDirPath: options.configPath, | ||
babelConfigPath: '@storybook/angular/dist/server/babel_config', | ||
}); | ||
|
||
runWithRequireContext(content, contextOpts); | ||
|
||
return { | ||
framework: 'angular', | ||
renderTree: require.requireActual('./renderTree').default, | ||
renderShallowTree: () => { | ||
throw new Error('Shallow renderer is not supported for angular'); | ||
}, | ||
storybook: require.requireActual('@storybook/angular'), | ||
}; | ||
} | ||
|
||
export default { | ||
load, | ||
test, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How are people expected to get |
||
import AngularSnapshotSerializer from 'jest-preset-angular/AngularSnapshotSerializer'; | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
import HTMLCommentSerializer from 'jest-preset-angular/HTMLCommentSerializer'; | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
import { TestBed } from '@angular/core/testing'; | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing'; | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
import { NO_ERRORS_SCHEMA } from '@angular/core'; | ||
import { addSerializer } from 'jest-specific-snapshot'; | ||
import { initModuleData } from './helpers.ts'; | ||
|
||
addSerializer(HTMLCommentSerializer); | ||
addSerializer(AngularSnapshotSerializer); | ||
|
||
function getRenderedTree(story, context) { | ||
const currentStory = story.render(context); | ||
|
||
const { moduleMeta, AppComponent } = initModuleData(currentStory); | ||
|
||
TestBed.configureTestingModule({ | ||
imports: [...moduleMeta.imports], | ||
declarations: [...moduleMeta.declarations], | ||
providers: [...moduleMeta.providers], | ||
schemas: [NO_ERRORS_SCHEMA, ...moduleMeta.schemas], | ||
bootstrap: [...moduleMeta.bootstrap], | ||
}); | ||
|
||
TestBed.overrideModule(BrowserDynamicTestingModule, { | ||
set: { | ||
entryComponents: [...moduleMeta.entryComponents], | ||
}, | ||
}); | ||
|
||
return TestBed.compileComponents().then(() => { | ||
const tree = TestBed.createComponent(AppComponent); | ||
tree.detectChanges(); | ||
|
||
return tree; | ||
}); | ||
} | ||
|
||
export default getRenderedTree; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
export interface NgModuleMetadata { | ||
declarations?: Array<any>; | ||
entryComponents?: Array<any>; | ||
imports?: Array<any>; | ||
schemas?: Array<any>; | ||
providers?: Array<any>; | ||
} | ||
|
||
export interface ICollection { | ||
[p: string]: any; | ||
} | ||
|
||
export interface NgStory { | ||
component?: any; | ||
props: ICollection; | ||
propsMeta?: ICollection; | ||
moduleMetadata?: NgModuleMetadata; | ||
template?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import path from 'path'; | ||
|
||
const babel = require('babel-core'); | ||
|
||
function getConfigContent({ resolvedConfigDirPath, configPath, babelConfigPath }) { | ||
const loadBabelConfig = require.requireActual(babelConfigPath).default; | ||
const babelConfig = loadBabelConfig(resolvedConfigDirPath); | ||
return babel.transformFileSync(configPath, babelConfig).code; | ||
} | ||
|
||
function load({ configDirPath, babelConfigPath }) { | ||
const resolvedConfigDirPath = path.resolve(configDirPath || '.storybook'); | ||
const configPath = path.join(resolvedConfigDirPath, 'config.js'); | ||
|
||
const content = getConfigContent({ resolvedConfigDirPath, configPath, babelConfigPath }); | ||
const contextOpts = { filename: configPath, dirname: resolvedConfigDirPath }; | ||
|
||
return { | ||
content, | ||
contextOpts, | ||
}; | ||
} | ||
|
||
export default load; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import loaderReact from './react/loader'; | ||
import loaderRn from './rn/loader'; | ||
import loaderAngular from './angular/loader'; | ||
import loaderVue from './vue/loader'; | ||
|
||
const loaders = [loaderReact, loaderAngular, loaderRn, loaderVue]; | ||
|
||
function loadFramework(options) { | ||
const loader = loaders.find(frameworkLoader => frameworkLoader.test(options)); | ||
|
||
if (!loader) { | ||
throw new Error('storyshots is intended only to be used with storybook'); | ||
} | ||
|
||
return loader.load(options); | ||
} | ||
|
||
export default loadFramework; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a note explaining why we can't have it as a peer dep
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, "yo" is probably a typo =D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add the shell command to copypaste: