Skip to content

Commit

Permalink
test: add browser integration test
Browse files Browse the repository at this point in the history
Run component generation in browser
  • Loading branch information
dpilch committed Oct 19, 2021
1 parent 74f860c commit e3097ba
Show file tree
Hide file tree
Showing 17 changed files with 256 additions and 67 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ module.exports = {
'.eslintrc.js',
'commitlint.config.js',
'packages/amplify-ui-codegen-schema',
'packages/browser-integration-test',
'ui-components',
'*.md',
'cypress',
'packages/test-generator/test-app-templates',
'packages/test-generator/browser-integration-test-templates',
],
extends: [
'plugin:@typescript-eslint/recommended',
Expand Down
29 changes: 28 additions & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ jobs:
run: npm run build
- name: Execute test-generator
working-directory: amplify-codegen-ui-staging/packages/test-generator
run: node ./dist/lib/generators/GenerateTestApp.js
run: node ./dist/generators/GenerateTestApp.js
- name: Create test app with dependencies
working-directory: .
run: |
Expand All @@ -130,3 +130,30 @@ jobs:
build: npm run build
start: npm start
wait-on: 'http://localhost:3000'

browser-integration-test:
runs-on: ubuntu-latest
steps:
- name: Checkout Studio Codegen
uses: actions/checkout@v2
- name: Setup Node.js LTS
uses: actions/setup-node@v2
with:
node-version: lts/*
- name: Install packages
run: npm ci
- name: Lerna bootstrap
run: lerna bootstrap
- name: Build
run: npm run build
- name: Setup Browser Integration Test
run: |
npm run browser-integration:clean
npm run browser-integration:setup
- name: Cypress run
uses: cypress-io/github-action@v2
with:
working-directory: packages/browser-integration-test
install: false
start: npm start
wait-on: 'http://localhost:3000'
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ dist/**
**/.rollup.cache

ui-components
browser-integration-test
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
"format:check": "prettier --check 'packages/*/lib/**/*.{js,jsx,ts,tsx}'",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"test:generate-test-app": "npx rimraf packages/test-generator/test-app-templates/src/ui-components && lerna run build --stream && node packages/test-generator/dist/lib/generators/GenerateTestApp.js"
"test:generate-test-app": "npx rimraf packages/test-generator/test-app-templates/src/ui-components && lerna run build --stream && node packages/test-generator/dist/generators/GenerateTestApp.js",
"browser-integration:setup": "npm run browser-integration:create && npm run browser-integration:install",
"browser-integration:create": "(cd packages && npx create-react-app browser-integration-test --use-npm --template typescript) && echo 'SKIP_PREFLIGHT_CHECK=true' > packages/browser-integration-test/.env && cp -r packages/test-generator/browser-integration-test-templates/* packages/browser-integration-test",
"browser-integration:install": "lerna bootstrap && lerna add --scope browser-integration-test @amzn/studio-ui-codegen-react && lerna add --scope browser-integration-test @amzn/test-generator && lerna add --no-ci --scope browser-integration-test cypress",
"browser-integration:clean": "npx rimraf packages/browser-integration-test"
},
"files": [],
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions packages/test-generator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ Test components will be rendered with both source and usage docs to STDOUT as ma
lerna bootstrap
lerna run build
# And either render to STDOUT or a file
node packages/test-generator/dist/index.js
node packages/test-generator/dist/index.js > test-generator-output.md
node packages/test-generator/dist/scripts/run.js
node packages/test-generator/dist/scripts/run.js > test-generator-output.md
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
describe('Generate Components', () => {
it('Generates all components', () => {
cy.visit('http://localhost:3000');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { BrowserTestGenerator } from '@amzn/test-generator';
import logo from './logo.svg';
import './App.css';

function App() {
const generator = new BrowserTestGenerator({
writeToLogger: true,
writeToDisk: false,
disabledSchemas: [
'BasicComponentCustom', // TODO: Add as part of basic components part 2
'BasicComponentDivider', // TODO: Add as part of basic components part 2
'BasicComponentFlex', // TODO: Add as part of basic components part 2
'BasicComponentImage', // TODO: Add as part of basic components part 2
],
});
generator.generate();
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
Learn React
</a>
</header>
</div>
);
}

export default App;
37 changes: 37 additions & 0 deletions packages/test-generator/lib/generators/BrowserTestGenerator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/* Test Generator to be used in the browser environment */
import { StudioComponent, StudioTheme } from '@amzn/amplify-ui-codegen-schema';
import { AmplifyRenderer, ReactThemeStudioTemplateRenderer } from '@amzn/studio-ui-codegen-react';
import { TestGenerator } from './TestGenerator';

export class BrowserTestGenerator extends TestGenerator {
writeComponentToDisk() {} // no-op

writeThemeToDisk() {} // no-op

renderComponent(component: StudioComponent) {
return {
renderedComponent: new AmplifyRenderer(component, this.renderConfig).renderComponentOnly(),
appSample: { compText: '', importsText: '' },
};
}

renderTheme(theme: StudioTheme) {
return new ReactThemeStudioTemplateRenderer(theme, this.renderConfig).renderComponent();
}
}
4 changes: 2 additions & 2 deletions packages/test-generator/lib/generators/GenerateTestApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
import { TestGenerator } from './TestGenerator';
import { NodeTestGenerator } from './NodeTestGenerator';

new TestGenerator({
new NodeTestGenerator({
writeToLogger: false,
writeToDisk: true,
disabledSchemas: [
Expand Down
66 changes: 66 additions & 0 deletions packages/test-generator/lib/generators/NodeTestGenerator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/* Test Generator to be used in the Node environment */
import { StudioComponent, StudioTheme } from '@amzn/amplify-ui-codegen-schema';
import { StudioTemplateRendererManager, StudioTemplateRendererFactory } from '@amzn/studio-ui-codegen';
import { AmplifyRenderer, ReactOutputConfig, ReactThemeStudioTemplateRenderer } from '@amzn/studio-ui-codegen-react';
import path from 'path';
import { TestGenerator, TestGeneratorParams } from './TestGenerator';

export class NodeTestGenerator extends TestGenerator {
private readonly componentRendererFactory: any;

private readonly themeRendererFactory: any;

private readonly rendererManager: any;

private readonly themeRendererManager: any;

constructor(params: TestGeneratorParams) {
super(params);
this.componentRendererFactory = new StudioTemplateRendererFactory(
(component: StudioComponent) => new AmplifyRenderer(component, this.renderConfig),
);
this.themeRendererFactory = new StudioTemplateRendererFactory(
(theme: StudioTheme) => new ReactThemeStudioTemplateRenderer(theme, this.renderConfig),
);
const outputPathDir = path.resolve(path.join(__dirname, '..', '..', 'test-app-templates', 'src', 'ui-components'));
const outputConfig: ReactOutputConfig = { outputPathDir };
this.rendererManager = new StudioTemplateRendererManager(this.componentRendererFactory, outputConfig);
this.themeRendererManager = new StudioTemplateRendererManager(this.themeRendererFactory, outputConfig);
}

writeComponentToDisk(component: StudioComponent) {
this.rendererManager.renderSchemaToTemplate(component);
}

renderComponent(component: StudioComponent) {
const buildRenderer = this.componentRendererFactory.buildRenderer(component);
const renderedComponent = buildRenderer.renderComponentOnly();
const appSample = buildRenderer.renderSampleCodeSnippet();
return { renderedComponent, appSample };
}

writeThemeToDisk(theme: StudioTheme) {
this.themeRendererManager.renderSchemaToTemplate(theme);
}

renderTheme(theme: StudioTheme) {
const buildRenderer = this.themeRendererFactory.buildRenderer(theme);
return buildRenderer.renderComponent();
}
}
83 changes: 31 additions & 52 deletions packages/test-generator/lib/generators/TestGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,17 @@
limitations under the License.
*/
import { StudioComponent, StudioTheme } from '@amzn/amplify-ui-codegen-schema';
import { StudioTemplateRendererManager, StudioTemplateRendererFactory } from '@amzn/studio-ui-codegen';
import {
AmplifyRenderer,
ReactOutputConfig,
ModuleKind,
ScriptTarget,
ScriptKind,
ReactThemeStudioTemplateRenderer,
ReactRenderConfig,
} from '@amzn/studio-ui-codegen-react';
import path from 'path';
import { ModuleKind, ScriptTarget, ScriptKind, ReactRenderConfig } from '@amzn/studio-ui-codegen-react';
import log from 'loglevel';
import { ComponentSchemas, ThemeSchemas } from '../index';
import * as ComponentSchemas from '../components';
import * as ThemeSchemas from '../themes';

const DEFAULT_RENDER_CONFIG = {
module: ModuleKind.CommonJS,
target: ScriptTarget.ES2015,
script: ScriptKind.TSX,
};

Error.stackTraceLimit = Infinity;

log.setLevel('info');

export type TestGeneratorParams = {
Expand All @@ -45,38 +34,16 @@ export type TestGeneratorParams = {
disabledSchemas?: string[];
};

export class TestGenerator {
private readonly params: TestGeneratorParams;

private readonly componentRendererFactory: any;

private readonly themeRendererFactory: any;
export abstract class TestGenerator {
protected readonly params: TestGeneratorParams;

private readonly rendererManager: any;

private readonly themeRendererManager: any;
protected readonly renderConfig: ReactRenderConfig;

constructor(params: TestGeneratorParams) {
this.params = params;
const mergedRenderConfig = { ...DEFAULT_RENDER_CONFIG, ...params.renderConfigOverride };
this.componentRendererFactory = new StudioTemplateRendererFactory(
(component: StudioComponent) => new AmplifyRenderer(component, mergedRenderConfig),
);
this.themeRendererFactory = new StudioTemplateRendererFactory(
(theme: StudioTheme) => new ReactThemeStudioTemplateRenderer(theme, mergedRenderConfig),
);
const outputPathDir = path.resolve(
path.join(__dirname, '..', '..', '..', 'test-app-templates', 'src', 'ui-components'),
);
const outputConfig: ReactOutputConfig = { outputPathDir };
this.rendererManager = new StudioTemplateRendererManager(this.componentRendererFactory, outputConfig);
this.themeRendererManager = new StudioTemplateRendererManager(this.themeRendererFactory, outputConfig);
this.renderConfig = { ...DEFAULT_RENDER_CONFIG, ...params.renderConfigOverride };
}

private decorateTypescriptWithMarkdown = (typescriptSource: string): string => {
return `\`\`\`typescript jsx\n${typescriptSource}\n\`\`\``;
};

generate = () => {
const renderErrors: { [key: string]: any } = {};

Expand All @@ -86,24 +53,22 @@ export class TestGenerator {
}
try {
if (this.params.writeToDisk) {
this.rendererManager.renderSchemaToTemplate(schema as any);
this.writeComponentToDisk(schema as StudioComponent);
}

if (this.params.writeToLogger) {
const buildRenderer = this.componentRendererFactory.buildRenderer(schema as any);
const compOnly = buildRenderer.renderComponentOnly();
const compOnlyAppSample = buildRenderer.renderSampleCodeSnippet();
const { renderedComponent, appSample } = this.renderComponent(schema as StudioComponent);
log.info(`# ${name}`);
log.info('## Component Only Output');
log.info('### componentImports');
log.info(this.decorateTypescriptWithMarkdown(compOnly.importsText));
log.info(this.decorateTypescriptWithMarkdown(renderedComponent.importsText));
log.info('### componentText');
log.info(this.decorateTypescriptWithMarkdown(compOnly.compText));
log.info(this.decorateTypescriptWithMarkdown(renderedComponent.compText));
log.info('## Code Snippet Output');
log.info('### componentImports');
log.info(this.decorateTypescriptWithMarkdown(compOnlyAppSample.importsText));
log.info(this.decorateTypescriptWithMarkdown(appSample.importsText));
log.info('### componentText');
log.info(this.decorateTypescriptWithMarkdown(compOnlyAppSample.compText));
log.info(this.decorateTypescriptWithMarkdown(appSample.compText));
}
} catch (err) {
renderErrors[name] = err;
Expand All @@ -116,15 +81,14 @@ export class TestGenerator {
}
try {
if (this.params.writeToDisk) {
this.themeRendererManager.renderSchemaToTemplate(schema as any);
this.writeThemeToDisk(schema as StudioTheme);
}

if (this.params.writeToLogger) {
const buildRenderer = this.themeRendererFactory.buildRenderer(schema as any);
const component = buildRenderer.renderComponent();
const theme = this.renderTheme(schema as StudioTheme);
log.info(`# ${name}`);
log.info('## Theme Output');
log.info(this.decorateTypescriptWithMarkdown(component.componentText));
log.info(this.decorateTypescriptWithMarkdown(theme.componentText));
}
} catch (err) {
renderErrors[name] = err;
Expand All @@ -140,4 +104,19 @@ export class TestGenerator {
throw new Error('Not all tests rendered successfully');
}
};

private decorateTypescriptWithMarkdown = (typescriptSource: string): string => {
return `\`\`\`typescript jsx\n${typescriptSource}\n\`\`\``;
};

abstract writeComponentToDisk(component: StudioComponent): void;

abstract writeThemeToDisk(theme: StudioTheme): void;

abstract renderComponent(component: StudioComponent): {
renderedComponent: { compText: string; importsText: string };
appSample: { compText: string; importsText: string };
};

abstract renderTheme(theme: StudioTheme): { componentText: string };
}
Loading

0 comments on commit e3097ba

Please sign in to comment.