From 3aa9edde7269ad8699e2afdf3bb2110126ef95b5 Mon Sep 17 00:00:00 2001 From: Remus Mate Date: Tue, 20 Feb 2024 12:51:01 +1100 Subject: [PATCH 01/10] implement single entry --- README.md | 10 ++++++++++ lib/defaultModules/entry.js | 1 + lib/defaultModules/useScope.js | 2 ++ lib/makeWebpackConfig.js | 3 +++ src/entry.js | 7 +++++++ src/frame.js | 2 ++ src/index.d.ts | 1 + src/index.js | 2 ++ src/preview.js | 2 ++ 9 files changed, 30 insertions(+) create mode 100644 lib/defaultModules/entry.js create mode 100644 src/entry.js diff --git a/README.md b/README.md index e89cc6f0..b2b78ac6 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ module.exports = { // Optional: title: 'My Awesome Library', + entry: './src/entry', themes: './src/themes', snippets: './playroom/snippets.js', frameComponent: './playroom/FrameComponent.js', @@ -158,6 +159,15 @@ export default function useScope() { }; ``` +## Custom Entry + +You can provide a custom entry file via the `entry` option, which is a path to a file that runs some code before everything else. For example, if you wanted to apply a CSS reset or other global styles, polyfills etc.: + +```js +import '../path/to/your/theming-system/reset'; +import '../path/to/your/theming-system/global-styles.css'; +``` + ## Theme Support If your component library has multiple themes, you can customise Playroom to render every theme simultaneously via the `themes` configuration option. diff --git a/lib/defaultModules/entry.js b/lib/defaultModules/entry.js new file mode 100644 index 00000000..ad37c334 --- /dev/null +++ b/lib/defaultModules/entry.js @@ -0,0 +1 @@ +// this doesn't do anything by default diff --git a/lib/defaultModules/useScope.js b/lib/defaultModules/useScope.js index 2d1ec238..5d922502 100644 --- a/lib/defaultModules/useScope.js +++ b/lib/defaultModules/useScope.js @@ -1 +1,3 @@ +import '../../src/entry'; + export default () => {}; diff --git a/lib/makeWebpackConfig.js b/lib/makeWebpackConfig.js index 0179abe9..8a532d55 100644 --- a/lib/makeWebpackConfig.js +++ b/lib/makeWebpackConfig.js @@ -56,6 +56,9 @@ module.exports = async (playroomConfig, options) => { }, extensions: ['.mjs', '.tsx', '.ts', '.jsx', '.js', '.json'], alias: { + __PLAYROOM_ALIAS__ENTRY__: playroomConfig.entry + ? relativeResolve(playroomConfig.entry) + : require.resolve('./defaultModules/entry'), __PLAYROOM_ALIAS__COMPONENTS__: relativeResolve( playroomConfig.components ), diff --git a/src/entry.js b/src/entry.js new file mode 100644 index 00000000..fce86c12 --- /dev/null +++ b/src/entry.js @@ -0,0 +1,7 @@ +let imported = false; + +if (!imported) { + imported = true; + // eslint-disable-next-line import/no-unresolved + require('__PLAYROOM_ALIAS__ENTRY__'); +} diff --git a/src/frame.js b/src/frame.js index 470b81da..acd63223 100644 --- a/src/frame.js +++ b/src/frame.js @@ -1,3 +1,5 @@ +import './entry'; + import { renderElement } from './render'; import Frame from './Playroom/Frame'; diff --git a/src/index.d.ts b/src/index.d.ts index 3c32b53d..791e1694 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,4 +1,5 @@ interface PlayroomConfig { + entry?: string; components: string; outputPath: string; title?: string; diff --git a/src/index.js b/src/index.js index 4bd28845..c015329a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,5 @@ +import './entry'; + import { renderElement } from './render'; import Playroom from './Playroom/Playroom'; import { StoreProvider } from './StoreContext/StoreContext'; diff --git a/src/preview.js b/src/preview.js index efae4509..42b72ca4 100644 --- a/src/preview.js +++ b/src/preview.js @@ -1,3 +1,5 @@ +import './entry'; + import { renderElement } from './render'; import Preview from './Playroom/Preview'; From 9cfc64773e0ab439564770f63a90ed0c323da5b4 Mon Sep 17 00:00:00 2001 From: Remus Mate Date: Tue, 20 Feb 2024 12:51:16 +1100 Subject: [PATCH 02/10] add integration tests for single entry --- cypress/e2e/entry.cy.js | 36 +++++++++++++++++++ cypress/projects/typescript/entry.ts | 3 ++ .../projects/typescript/playroom.config.js | 1 + cypress/projects/typescript/state.ts | 15 ++++++++ 4 files changed, 55 insertions(+) create mode 100644 cypress/e2e/entry.cy.js create mode 100644 cypress/projects/typescript/entry.ts create mode 100644 cypress/projects/typescript/state.ts diff --git a/cypress/e2e/entry.cy.js b/cypress/e2e/entry.cy.js new file mode 100644 index 00000000..a8257fc8 --- /dev/null +++ b/cypress/e2e/entry.cy.js @@ -0,0 +1,36 @@ +import { assertPreviewContains, typeCode, visit } from '../support/utils'; + +describe('entry', () => { + const assertGlobalCounter = () => + cy.window().its('counter').should('equal', 1); + + describe('loads the entry only once', () => { + it('for main app', () => { + cy.visit('http://localhost:9002'); + // introduce some delay to make sure everything loads + typeCode('-'); + + assertGlobalCounter(); + }); + + it('for frames', () => { + visit('http://localhost:9002'); + // introduce some delay to make sure everything loads + typeCode('-'); + + assertGlobalCounter(); + }); + + it('for preview', () => { + cy.visit( + 'http://localhost:9002/preview#code=N4Igxg9gJgpiBcIC0IC%2BQ' + ).then(() => { + cy.get('[data-testid="splashscreen"]').should('not.be.visible'); + }); + // wait for rendering to finish to make sure everything loads + assertPreviewContains('-'); + + assertGlobalCounter(); + }); + }); +}); diff --git a/cypress/projects/typescript/entry.ts b/cypress/projects/typescript/entry.ts new file mode 100644 index 00000000..6fb7551a --- /dev/null +++ b/cypress/projects/typescript/entry.ts @@ -0,0 +1,3 @@ +import { increment } from './state'; + +increment(); diff --git a/cypress/projects/typescript/playroom.config.js b/cypress/projects/typescript/playroom.config.js index 83629b91..e06661e7 100644 --- a/cypress/projects/typescript/playroom.config.js +++ b/cypress/projects/typescript/playroom.config.js @@ -1,4 +1,5 @@ module.exports = { + entry: './entry.ts', components: './components.ts', snippets: './snippets.ts', outputPath: './dist', diff --git a/cypress/projects/typescript/state.ts b/cypress/projects/typescript/state.ts new file mode 100644 index 00000000..facb3e6c --- /dev/null +++ b/cypress/projects/typescript/state.ts @@ -0,0 +1,15 @@ +/* eslint-disable no-console */ + +declare global { + interface Window { + counter: number; + } +} + +window.counter = 0; + +export function increment() { + window.counter++; + + console.log('incremented', window.counter); +} From c443e0d36421e6c887cdd6e464981f0df365405d Mon Sep 17 00:00:00 2001 From: Remus Mate Date: Tue, 20 Feb 2024 15:03:45 +1100 Subject: [PATCH 03/10] use mjs --- lib/defaultModules/useScope.js | 2 +- src/{entry.js => entry.mjs} | 2 +- src/frame.js | 2 +- src/index.d.ts | 2 +- src/index.js | 2 +- src/preview.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename src/{entry.js => entry.mjs} (73%) diff --git a/lib/defaultModules/useScope.js b/lib/defaultModules/useScope.js index 5d922502..18628aae 100644 --- a/lib/defaultModules/useScope.js +++ b/lib/defaultModules/useScope.js @@ -1,3 +1,3 @@ -import '../../src/entry'; +import '../../src/entry.mjs'; export default () => {}; diff --git a/src/entry.js b/src/entry.mjs similarity index 73% rename from src/entry.js rename to src/entry.mjs index fce86c12..638f1bb0 100644 --- a/src/entry.js +++ b/src/entry.mjs @@ -3,5 +3,5 @@ let imported = false; if (!imported) { imported = true; // eslint-disable-next-line import/no-unresolved - require('__PLAYROOM_ALIAS__ENTRY__'); + import('__PLAYROOM_ALIAS__ENTRY__'); } diff --git a/src/frame.js b/src/frame.js index acd63223..acd630ad 100644 --- a/src/frame.js +++ b/src/frame.js @@ -1,4 +1,4 @@ -import './entry'; +import './entry.mjs'; import { renderElement } from './render'; import Frame from './Playroom/Frame'; diff --git a/src/index.d.ts b/src/index.d.ts index 791e1694..5b3011bc 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,8 +1,8 @@ interface PlayroomConfig { - entry?: string; components: string; outputPath: string; title?: string; + entry?: string; themes?: string; widths?: number[]; snippets?: Snippet[]; diff --git a/src/index.js b/src/index.js index c015329a..ddc2ef7c 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import './entry'; +import './entry.mjs'; import { renderElement } from './render'; import Playroom from './Playroom/Playroom'; diff --git a/src/preview.js b/src/preview.js index 42b72ca4..c617c5a0 100644 --- a/src/preview.js +++ b/src/preview.js @@ -1,4 +1,4 @@ -import './entry'; +import './entry.mjs'; import { renderElement } from './render'; import Preview from './Playroom/Preview'; From 4eea27bd93707465ed88900231c533b47902591d Mon Sep 17 00:00:00 2001 From: Remus Mate Date: Tue, 20 Feb 2024 15:20:42 +1100 Subject: [PATCH 04/10] use live module bindings --- cypress/projects/typescript/entry.mjs | 5 +++++ cypress/projects/typescript/entry.ts | 3 --- cypress/projects/typescript/playroom.config.js | 2 +- cypress/projects/typescript/{state.ts => state.mjs} | 10 ++-------- 4 files changed, 8 insertions(+), 12 deletions(-) create mode 100644 cypress/projects/typescript/entry.mjs delete mode 100644 cypress/projects/typescript/entry.ts rename cypress/projects/typescript/{state.ts => state.mjs} (51%) diff --git a/cypress/projects/typescript/entry.mjs b/cypress/projects/typescript/entry.mjs new file mode 100644 index 00000000..0fdba2d4 --- /dev/null +++ b/cypress/projects/typescript/entry.mjs @@ -0,0 +1,5 @@ +import { counter, increment } from './state.mjs'; + +export default counter; + +increment(); diff --git a/cypress/projects/typescript/entry.ts b/cypress/projects/typescript/entry.ts deleted file mode 100644 index 6fb7551a..00000000 --- a/cypress/projects/typescript/entry.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { increment } from './state'; - -increment(); diff --git a/cypress/projects/typescript/playroom.config.js b/cypress/projects/typescript/playroom.config.js index e06661e7..46645435 100644 --- a/cypress/projects/typescript/playroom.config.js +++ b/cypress/projects/typescript/playroom.config.js @@ -1,5 +1,5 @@ module.exports = { - entry: './entry.ts', + entry: './entry.mjs', components: './components.ts', snippets: './snippets.ts', outputPath: './dist', diff --git a/cypress/projects/typescript/state.ts b/cypress/projects/typescript/state.mjs similarity index 51% rename from cypress/projects/typescript/state.ts rename to cypress/projects/typescript/state.mjs index facb3e6c..fd80dfc7 100644 --- a/cypress/projects/typescript/state.ts +++ b/cypress/projects/typescript/state.mjs @@ -1,15 +1,9 @@ /* eslint-disable no-console */ -declare global { - interface Window { - counter: number; - } -} - -window.counter = 0; +export let counter = 0; export function increment() { - window.counter++; + window.counter = ++counter; console.log('incremented', window.counter); } From d32d505d15c95a44e2821790b3c5d7258b8a8a44 Mon Sep 17 00:00:00 2001 From: Remus Mate Date: Tue, 20 Feb 2024 16:03:23 +1100 Subject: [PATCH 05/10] add changeset --- .changeset/strong-suits-end.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .changeset/strong-suits-end.md diff --git a/.changeset/strong-suits-end.md b/.changeset/strong-suits-end.md new file mode 100644 index 00000000..12dbf977 --- /dev/null +++ b/.changeset/strong-suits-end.md @@ -0,0 +1,12 @@ +--- +'playroom': minor +--- + +Add custom entry file support + +You can provide a custom entry file via the `entry` option, which is a path to a file that runs some code before everything else. For example, if you wanted to apply a CSS reset or other global styles, polyfills etc.: + +```js +import '../path/to/your/theming-system/reset'; +import '../path/to/your/theming-system/global-styles.css'; +``` From e2b591893b143d2d8d62666709a71a388f846564 Mon Sep 17 00:00:00 2001 From: Remus Mate Date: Tue, 20 Feb 2024 16:19:27 +1100 Subject: [PATCH 06/10] simplify custom entry --- lib/defaultModules/useScope.js | 2 -- lib/makeWebpackConfig.js | 12 ++++++------ src/entry.mjs | 7 ------- src/frame.js | 2 -- src/index.js | 2 -- src/preview.js | 2 -- 6 files changed, 6 insertions(+), 21 deletions(-) delete mode 100644 src/entry.mjs diff --git a/lib/defaultModules/useScope.js b/lib/defaultModules/useScope.js index 18628aae..2d1ec238 100644 --- a/lib/defaultModules/useScope.js +++ b/lib/defaultModules/useScope.js @@ -1,3 +1 @@ -import '../../src/entry.mjs'; - export default () => {}; diff --git a/lib/makeWebpackConfig.js b/lib/makeWebpackConfig.js index 8a532d55..e952c8c8 100644 --- a/lib/makeWebpackConfig.js +++ b/lib/makeWebpackConfig.js @@ -36,13 +36,16 @@ module.exports = async (playroomConfig, options) => { } const staticTypes = await getStaticTypes(playroomConfig); + const customEntry = playroomConfig.entry + ? relativeResolve(playroomConfig.entry) + : require.resolve('./defaultModules/entry'); const ourConfig = { mode: options.production ? 'production' : 'development', entry: { - index: [require.resolve('../src/index.js')], - frame: [require.resolve('../src/frame.js')], - preview: [require.resolve('../src/preview.js')], + index: [customEntry, require.resolve('../src/index.js')], + frame: [customEntry, require.resolve('../src/frame.js')], + preview: [customEntry, require.resolve('../src/preview.js')], }, output: { filename: '[name].[contenthash].js', @@ -56,9 +59,6 @@ module.exports = async (playroomConfig, options) => { }, extensions: ['.mjs', '.tsx', '.ts', '.jsx', '.js', '.json'], alias: { - __PLAYROOM_ALIAS__ENTRY__: playroomConfig.entry - ? relativeResolve(playroomConfig.entry) - : require.resolve('./defaultModules/entry'), __PLAYROOM_ALIAS__COMPONENTS__: relativeResolve( playroomConfig.components ), diff --git a/src/entry.mjs b/src/entry.mjs deleted file mode 100644 index 638f1bb0..00000000 --- a/src/entry.mjs +++ /dev/null @@ -1,7 +0,0 @@ -let imported = false; - -if (!imported) { - imported = true; - // eslint-disable-next-line import/no-unresolved - import('__PLAYROOM_ALIAS__ENTRY__'); -} diff --git a/src/frame.js b/src/frame.js index acd630ad..470b81da 100644 --- a/src/frame.js +++ b/src/frame.js @@ -1,5 +1,3 @@ -import './entry.mjs'; - import { renderElement } from './render'; import Frame from './Playroom/Frame'; diff --git a/src/index.js b/src/index.js index ddc2ef7c..4bd28845 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,3 @@ -import './entry.mjs'; - import { renderElement } from './render'; import Playroom from './Playroom/Playroom'; import { StoreProvider } from './StoreContext/StoreContext'; diff --git a/src/preview.js b/src/preview.js index c617c5a0..efae4509 100644 --- a/src/preview.js +++ b/src/preview.js @@ -1,5 +1,3 @@ -import './entry.mjs'; - import { renderElement } from './render'; import Preview from './Playroom/Preview'; From 504da1a45531055d99129b541e92b2c5a6982f4a Mon Sep 17 00:00:00 2001 From: Remus Mate Date: Wed, 21 Feb 2024 17:39:13 +1100 Subject: [PATCH 07/10] add the possibility to define multiple entries --- lib/makeWebpackConfig.js | 24 ++++++++++++++++++------ src/index.d.ts | 8 +++++++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/lib/makeWebpackConfig.js b/lib/makeWebpackConfig.js index e952c8c8..fef0e160 100644 --- a/lib/makeWebpackConfig.js +++ b/lib/makeWebpackConfig.js @@ -36,16 +36,28 @@ module.exports = async (playroomConfig, options) => { } const staticTypes = await getStaticTypes(playroomConfig); - const customEntry = playroomConfig.entry - ? relativeResolve(playroomConfig.entry) - : require.resolve('./defaultModules/entry'); + + const customEntries = Object.fromEntries( + ['index', 'frame', 'preview'].map((entryName) => { + const customEntry = + typeof playroomConfig.entry === 'object' + ? playroomConfig.entry[entryName] + : playroomConfig.entry; + return [ + entryName, + customEntry + ? relativeResolve(customEntry) + : require.resolve('./defaultModules/entry'), + ]; + }) + ); const ourConfig = { mode: options.production ? 'production' : 'development', entry: { - index: [customEntry, require.resolve('../src/index.js')], - frame: [customEntry, require.resolve('../src/frame.js')], - preview: [customEntry, require.resolve('../src/preview.js')], + index: [customEntries.index, require.resolve('../src/index.js')], + frame: [customEntries.frame, require.resolve('../src/frame.js')], + preview: [customEntries.preview, require.resolve('../src/preview.js')], }, output: { filename: '[name].[contenthash].js', diff --git a/src/index.d.ts b/src/index.d.ts index 5b3011bc..5934e4ac 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -2,7 +2,13 @@ interface PlayroomConfig { components: string; outputPath: string; title?: string; - entry?: string; + entry?: + | string + | { + index?: string; + frame?: string; + preview?: string; + }; themes?: string; widths?: number[]; snippets?: Snippet[]; From 4e3c67095b35d712908f3e85c85a87280323b7c2 Mon Sep 17 00:00:00 2001 From: Remus Mate Date: Wed, 21 Feb 2024 17:39:26 +1100 Subject: [PATCH 08/10] add tests for multiple entries --- cypress/e2e/entry.cy.js | 79 ++++++++++++++++------ cypress/projects/themed/entry.js | 1 + cypress/projects/themed/playroom.config.js | 3 + cypress/support/utils.js | 44 ++++++------ package.json | 1 + pnpm-lock.yaml | 18 +++++ 6 files changed, 100 insertions(+), 46 deletions(-) create mode 100644 cypress/projects/themed/entry.js diff --git a/cypress/e2e/entry.cy.js b/cypress/e2e/entry.cy.js index a8257fc8..adde284e 100644 --- a/cypress/e2e/entry.cy.js +++ b/cypress/e2e/entry.cy.js @@ -1,36 +1,71 @@ -import { assertPreviewContains, typeCode, visit } from '../support/utils'; +import { + assertPreviewContains, + cleanUp, + getFirstFrame, + typeCode, + visit, +} from '../support/utils'; -describe('entry', () => { - const assertGlobalCounter = () => - cy.window().its('counter').should('equal', 1); +const assertGlobalCounter = () => cy.window().its('counter').should('equal', 1); +const assertGlobalCounterInIframe = ($iframe) => + cy.wrap($iframe[0].contentWindow).its('counter').should('equal', 1); - describe('loads the entry only once', () => { - it('for main app', () => { - cy.visit('http://localhost:9002'); - // introduce some delay to make sure everything loads - typeCode('-'); +describe('Entry', () => { + afterEach(() => { + cleanUp(); + }); + + describe('single entry', () => { + describe('loads the entry only once', () => { + it('for main app', () => { + cy.visit('http://localhost:9002'); + // introduce some delay to make sure everything loads + typeCode('-'); + + assertGlobalCounter(); + }); + + it('for frames', () => { + visit('http://localhost:9002'); + // introduce some delay to make sure everything loads + typeCode('-'); + + getFirstFrame().then(($frame) => { + assertGlobalCounterInIframe($frame); + }); + }); + + it('for preview', () => { + cy.visit( + 'http://localhost:9002/preview#code=N4Igxg9gJgpiBcIC0IC%2BQ' + ).then(() => { + cy.get('[data-testid="splashscreen"]').should('not.be.visible'); + }); + // wait for rendering to finish to make sure everything loads + assertPreviewContains('-'); - assertGlobalCounter(); + assertGlobalCounter(); + }); }); + }); - it('for frames', () => { - visit('http://localhost:9002'); + describe('multiple entries', () => { + it('loads the entry for frames', () => { + visit('http://localhost:9001/index.html'); // introduce some delay to make sure everything loads typeCode('-'); - assertGlobalCounter(); + getFirstFrame().then(($frame) => { + assertGlobalCounterInIframe($frame); + }); }); - it('for preview', () => { - cy.visit( - 'http://localhost:9002/preview#code=N4Igxg9gJgpiBcIC0IC%2BQ' - ).then(() => { - cy.get('[data-testid="splashscreen"]').should('not.be.visible'); - }); - // wait for rendering to finish to make sure everything loads - assertPreviewContains('-'); + it('does not load the entry for main app', () => { + visit('http://localhost:9001/index.html'); + // introduce some delay to make sure everything loads + typeCode('-'); - assertGlobalCounter(); + cy.window().its('counter').should('not.exist'); }); }); }); diff --git a/cypress/projects/themed/entry.js b/cypress/projects/themed/entry.js new file mode 100644 index 00000000..6346f1a5 --- /dev/null +++ b/cypress/projects/themed/entry.js @@ -0,0 +1 @@ +window.counter = 1; diff --git a/cypress/projects/themed/playroom.config.js b/cypress/projects/themed/playroom.config.js index 59b48319..a8003c11 100644 --- a/cypress/projects/themed/playroom.config.js +++ b/cypress/projects/themed/playroom.config.js @@ -1,4 +1,7 @@ module.exports = { + entry: { + frame: './entry', + }, components: './components', snippets: './snippets', themes: './themes', diff --git a/cypress/support/utils.js b/cypress/support/utils.js index 9fb26739..968eb86b 100644 --- a/cypress/support/utils.js +++ b/cypress/support/utils.js @@ -1,5 +1,8 @@ // eslint-disable-next-line spaced-comment /// +// eslint-disable-next-line spaced-comment +/// +import 'cypress-iframe'; import dedent from 'dedent'; import { createUrl } from '../../utils'; @@ -9,22 +12,16 @@ const WAIT_FOR_FRAME_TO_RENDER = 1000; const getCodeEditor = () => cy.get('.CodeMirror-code'); -export const getPreviewFrames = () => cy.get('[data-testid="previewFrame"]'); - -export const getPreviewFrameNames = () => cy.get('[data-testid="frameName"]'); +const getPreviewFrameNames = () => cy.get('[data-testid="frameName"]'); -export const getFirstFrame = () => getPreviewFrames().first(); +export const getFirstFrame = () => + cy.frameLoaded('[data-testid="previewFrame"]:first'); export const visit = (url) => cy .visit(url) .reload() - .then(() => { - getFirstFrame().then( - ($iframe) => - new Cypress.Promise((resolve) => $iframe.on('load', resolve)) - ); - }); + .then(() => getFirstFrame()); export const typeCode = (code, { delay = 200 } = {}) => getCodeEditor() @@ -153,24 +150,23 @@ export const assertPreviewContains = (text) => expect(el.get(0).innerText).to.eq(text); }); +export const cleanUp = () => + cy + .window() + .then((win) => { + const { storageKey } = win.__playroomConfig__; + indexedDB.deleteDatabase(storageKey); + }) + .reload(); + export const loadPlayroom = (initialCode) => { const baseUrl = 'http://localhost:9000'; const visitUrl = initialCode ? createUrl({ baseUrl, code: dedent(initialCode) }) : baseUrl; - return cy - .visit(visitUrl) - .window() - .then((win) => { - const { storageKey } = win.__playroomConfig__; - indexedDB.deleteDatabase(storageKey); - }) - .reload() - .then(() => - getFirstFrame().then( - ($iframe) => - new Cypress.Promise((resolve) => $iframe.on('load', resolve)) - ) - ); + cy.visit(visitUrl); + cleanUp(); + + return getFirstFrame(); }; diff --git a/package.json b/package.json index 1ffde33f..75d5410f 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "@types/react-helmet": "^6.1.6", "concurrently": "^7.6.0", "cypress": "^12.0.2", + "cypress-iframe": "^1.0.1", "eslint": "^8.44.0", "eslint-config-seek": "^11.3.1", "husky": "^8.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd3efbf5..a9a6c570 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -193,6 +193,9 @@ devDependencies: cypress: specifier: ^12.0.2 version: 12.0.2 + cypress-iframe: + specifier: ^1.0.1 + version: 1.0.1(@types/cypress@1.1.3) eslint: specifier: ^8.44.0 version: 8.44.0 @@ -2668,6 +2671,13 @@ packages: '@types/node': 18.11.12 dev: false + /@types/cypress@1.1.3: + resolution: {integrity: sha512-OXe0Gw8LeCflkG1oPgFpyrYWJmEKqYncBsD/J0r17r0ETx/TnIGDNLwXt/pFYSYuYTpzcq1q3g62M9DrfsBL4g==} + deprecated: This is a stub types definition for cypress (https://cypress.io). cypress provides its own type definitions, so you don't need @types/cypress installed! + dependencies: + cypress: 12.0.2 + dev: true + /@types/eslint-scope@3.7.4: resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} dependencies: @@ -4398,6 +4408,14 @@ packages: is-git-repository: 1.1.1 dev: false + /cypress-iframe@1.0.1(@types/cypress@1.1.3): + resolution: {integrity: sha512-Ne+xkZmWMhfq3x6wbfzK/SzsVTCrJru3R3cLXsoSAZyfUtJDamXyaIieHXeea3pQDXF4wE2w4iUuvCYHhoD31g==} + peerDependencies: + '@types/cypress': ^1.1.0 + dependencies: + '@types/cypress': 1.1.3 + dev: true + /cypress@12.0.2: resolution: {integrity: sha512-WnLx1DpnbF1vbpDBkgP14rK5yS3U+Gvxrv2fsB4Owma26oIyENj7DDRnsJbSZuTfG4mcuUJxAkRHJR2wBqBfMA==} engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} From a6ce97545ff1a3c9374f573837083afecede74ac Mon Sep 17 00:00:00 2001 From: Remus Mate Date: Thu, 29 Feb 2024 12:37:21 +1100 Subject: [PATCH 09/10] update tests after merge --- cypress/e2e/entry.cy.js | 38 +++++++++++++++++++------------------- cypress/support/utils.js | 18 ++++++------------ 2 files changed, 25 insertions(+), 31 deletions(-) diff --git a/cypress/e2e/entry.cy.js b/cypress/e2e/entry.cy.js index adde284e..a3a3d5e5 100644 --- a/cypress/e2e/entry.cy.js +++ b/cypress/e2e/entry.cy.js @@ -1,14 +1,22 @@ import { assertPreviewContains, cleanUp, - getFirstFrame, + getPreviewFrames, typeCode, - visit, } from '../support/utils'; -const assertGlobalCounter = () => cy.window().its('counter').should('equal', 1); -const assertGlobalCounterInIframe = ($iframe) => - cy.wrap($iframe[0].contentWindow).its('counter').should('equal', 1); +const getFirstFrame = () => + getPreviewFrames() + .first() + .then( + ($iframe) => + new Cypress.Promise((resolve) => + $iframe.on('load', () => resolve($iframe)) + ) + ); + +const assertGlobalCounter = (subject = cy.window()) => + subject.its('counter').should('equal', 1); describe('Entry', () => { afterEach(() => { @@ -26,21 +34,15 @@ describe('Entry', () => { }); it('for frames', () => { - visit('http://localhost:9002'); + cy.visit('http://localhost:9002'); // introduce some delay to make sure everything loads typeCode('-'); - getFirstFrame().then(($frame) => { - assertGlobalCounterInIframe($frame); - }); + assertGlobalCounter(getFirstFrame().its('0.contentWindow')); }); it('for preview', () => { - cy.visit( - 'http://localhost:9002/preview#code=N4Igxg9gJgpiBcIC0IC%2BQ' - ).then(() => { - cy.get('[data-testid="splashscreen"]').should('not.be.visible'); - }); + cy.visit('http://localhost:9002/preview#code=N4Igxg9gJgpiBcIC0IC%2BQ'); // wait for rendering to finish to make sure everything loads assertPreviewContains('-'); @@ -51,17 +53,15 @@ describe('Entry', () => { describe('multiple entries', () => { it('loads the entry for frames', () => { - visit('http://localhost:9001/index.html'); + cy.visit('http://localhost:9001/index.html'); // introduce some delay to make sure everything loads typeCode('-'); - getFirstFrame().then(($frame) => { - assertGlobalCounterInIframe($frame); - }); + assertGlobalCounter(getFirstFrame().its('0.contentWindow')); }); it('does not load the entry for main app', () => { - visit('http://localhost:9001/index.html'); + cy.visit('http://localhost:9001/index.html'); // introduce some delay to make sure everything loads typeCode('-'); diff --git a/cypress/support/utils.js b/cypress/support/utils.js index 4f06031e..1a92b52d 100644 --- a/cypress/support/utils.js +++ b/cypress/support/utils.js @@ -1,8 +1,5 @@ // eslint-disable-next-line spaced-comment /// -// eslint-disable-next-line spaced-comment -/// -import 'cypress-iframe'; import dedent from 'dedent'; import { createUrl } from '../../utils'; @@ -11,10 +8,9 @@ import { isMac } from '../../src/utils/formatting'; const getCodeEditor = () => cy.get('.CodeMirror-code').then((editor) => cy.wrap(editor)); -const getPreviewFrameNames = () => cy.get('[data-testid="frameName"]'); +export const getPreviewFrames = () => cy.get('[data-testid="previewFrame"]'); -export const getFirstFrame = () => - cy.frameLoaded('[data-testid="previewFrame"]:first'); +export const getPreviewFrameNames = () => cy.get('[data-testid="frameName"]'); export const typeCode = (code, { delay } = {}) => getCodeEditor().focused().type(code, { delay }); @@ -173,12 +169,10 @@ export const assertPreviewContains = (text) => }); export const cleanUp = () => - cy - .window() - .then((win) => { - const { storageKey } = win.__playroomConfig__; - indexedDB.deleteDatabase(storageKey); - }); + cy.window().then((win) => { + const { storageKey } = win.__playroomConfig__; + indexedDB.deleteDatabase(storageKey); + }); export const loadPlayroom = (initialCode) => { const baseUrl = 'http://localhost:9000'; From a3ca8891865edb99403a38b6d72c1226cce46a3d Mon Sep 17 00:00:00 2001 From: Remus Mate Date: Thu, 29 Feb 2024 13:00:03 +1100 Subject: [PATCH 10/10] a bit of gold plating --- cypress/e2e/entry.cy.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cypress/e2e/entry.cy.js b/cypress/e2e/entry.cy.js index a3a3d5e5..a4fceaf5 100644 --- a/cypress/e2e/entry.cy.js +++ b/cypress/e2e/entry.cy.js @@ -8,11 +8,9 @@ import { const getFirstFrame = () => getPreviewFrames() .first() - .then( - ($iframe) => - new Cypress.Promise((resolve) => - $iframe.on('load', () => resolve($iframe)) - ) + .then(cy.wrap) + .should( + ($frame) => expect($frame.get(0).contentDocument.body).to.not.be.empty ); const assertGlobalCounter = (subject = cy.window()) =>