From 6569464d905732744f01aead7a775daa50945ead Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Sat, 7 Dec 2024 14:41:00 -0600 Subject: [PATCH 01/18] feat(cli): allow common custom component files to be generated by scaffold command --- packages/cli/src/commands/generate/scaffold/scaffold.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/commands/generate/scaffold/scaffold.js b/packages/cli/src/commands/generate/scaffold/scaffold.js index ed0beb58da06..9069e1ed1702 100644 --- a/packages/cli/src/commands/generate/scaffold/scaffold.js +++ b/packages/cli/src/commands/generate/scaffold/scaffold.js @@ -584,11 +584,14 @@ const componentFiles = async ( const outputComponentName = component .replace(/Names/, pluralName) .replace(/Name/, singularName) + .replace(/\.ts\.template/, generateTypescript ? '.ts' : '.js') .replace(/\.tsx\.template/, generateTypescript ? '.tsx' : '.jsx') const finalFolder = (nestScaffoldByModel ? singularName + '/' : '') + - outputComponentName.replace(/\.[jt]sx?/, '') + outputComponentName + .replace(/\.test|\.mock|\.stories/, '') + .replace(/\.[jt]sx?/, '') const outputPath = path.join( getPaths().web.components, From bce7a71fce51badd7f80ce578e74a06261468a2e Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Sat, 7 Dec 2024 14:46:57 -0600 Subject: [PATCH 02/18] feat(cli): allow common custom page files to be generated by scaffold command --- packages/cli/src/commands/generate/scaffold/scaffold.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/commands/generate/scaffold/scaffold.js b/packages/cli/src/commands/generate/scaffold/scaffold.js index 9069e1ed1702..5ae516562cda 100644 --- a/packages/cli/src/commands/generate/scaffold/scaffold.js +++ b/packages/cli/src/commands/generate/scaffold/scaffold.js @@ -520,11 +520,14 @@ const pageFiles = async ( const outputPageName = page .replace(/Names/, pluralName) .replace(/Name/, singularName) + .replace(/\.ts\.template/, generateTypescript ? '.ts' : '.js') .replace(/\.tsx\.template/, generateTypescript ? '.tsx' : '.jsx') const finalFolder = (nestScaffoldByModel ? singularName + '/' : '') + - outputPageName.replace(/\.[jt]sx?/, '') + outputPageName + .replace(/\.test|\.mock|\.stories/, '') + .replace(/\.[jt]sx?/, '') const outputPath = path.join( getPaths().web.pages, From 3cd47bfae75abaddc6c1c240be5f0b6a0e33c8e1 Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Sat, 7 Dec 2024 16:16:39 -0600 Subject: [PATCH 03/18] chore: add changeset --- .changesets/11755.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changesets/11755.md diff --git a/.changesets/11755.md b/.changesets/11755.md new file mode 100644 index 000000000000..f6c96a06f798 --- /dev/null +++ b/.changesets/11755.md @@ -0,0 +1,3 @@ +- fix(cli): Allow common custom scaffold template files (#11755) by @esteban-url + +Adds the ability to generate test, stories and mock files when custom scaffold templates are in use. From ecf9f0ed386f934a5e913b9f132b3ff605468479 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Fri, 27 Dec 2024 08:50:49 +0100 Subject: [PATCH 04/18] more specific regex --- packages/cli/src/commands/generate/scaffold/scaffold.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/generate/scaffold/scaffold.js b/packages/cli/src/commands/generate/scaffold/scaffold.js index 5ae516562cda..c0ce366464cc 100644 --- a/packages/cli/src/commands/generate/scaffold/scaffold.js +++ b/packages/cli/src/commands/generate/scaffold/scaffold.js @@ -526,7 +526,7 @@ const pageFiles = async ( const finalFolder = (nestScaffoldByModel ? singularName + '/' : '') + outputPageName - .replace(/\.test|\.mock|\.stories/, '') + .replace(/(?:\.test|\.mock|\.stories)(?=\.ts)/, '') .replace(/\.[jt]sx?/, '') const outputPath = path.join( @@ -593,7 +593,7 @@ const componentFiles = async ( const finalFolder = (nestScaffoldByModel ? singularName + '/' : '') + outputComponentName - .replace(/\.test|\.mock|\.stories/, '') + .replace(/(?:\.test|\.mock|\.stories)(?=\.ts)/, '') .replace(/\.[jt]sx?/, '') const outputPath = path.join( From b633c6bffda5852c0d2727f78c830b6ff9709078 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Fri, 27 Dec 2024 12:24:23 +0100 Subject: [PATCH 05/18] add tests for mocks, tests etc --- .../scaffold/__tests__/scaffold.test.js | 80 ++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js index 29a6f85150c3..233ed5beb4fe 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js @@ -882,6 +882,28 @@ describe('custom templates', () => { 'export default function CustomPage() { return null }', 'web/generators/scaffold/pages/NamesPage.tsx.template': 'export default function CustomPluralPage() { return null }', + 'web/generators/scaffold/pages/NamePage.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', + 'web/generators/scaffold/pages/NamePage.test.tsx.template': + "it('renders page successfully', () => {})", + 'web/generators/scaffold/components/EditNameCell.tsx.template': + 'export const Success = () => null', + 'web/generators/scaffold/components/Name.tsx.template': + 'export default function ${singularPascalName}() { return null }', + 'web/generators/scaffold/components/NameCell.tsx.template': + 'export const Success = () => null', + 'web/generators/scaffold/components/NameForm.tsx.template': + 'export default function ${singularPascalName}Form() { return null }', + 'web/generators/scaffold/components/Names.tsx.template': + 'export default function ${singularPascalName}List() { return null }', + 'web/generators/scaffold/components/NamesCell.tsx.template': + 'export const Success = () => null', + 'web/generators/scaffold/components/NewName.tsx.template': + 'export default function New${singularPascalName}() { return null }', + 'web/generators/scaffold/components/Name.mock.ts.template': + 'export const standard = () => ({ custom: "" })', + 'web/generators/scaffold/components/Name.test.tsx.template': + "it('renders component successfully', () => {})", }, process.env.RWJS_CWD, ) @@ -900,8 +922,8 @@ describe('custom templates', () => { process.env.RWJS_CWD = originalRwjsCwd }) - test('returns exactly 19 files', () => { - expect(Object.keys(tsFiles).length).toEqual(19) + test('returns exactly 23 files', () => { + expect(Object.keys(tsFiles).length).toEqual(23) }) test('creates an Edit page', async () => { @@ -964,6 +986,60 @@ describe('custom templates', () => { `) }) + test('creates a Show page story', async () => { + expect( + tsFiles[ + path.normalize( + '/path/to/project/web/src/pages/Post/PostPage/PostPage.stories.tsx', + ) + ], + ).toMatchInlineSnapshot(` + "const customMeta = {} + export default customMeta + export const Primary = {} + " + `) + }) + + test('creates a Show page test', async () => { + expect( + tsFiles[ + path.normalize( + '/path/to/project/web/src/pages/Post/PostPage/PostPage.test.tsx', + ) + ], + ).toMatchInlineSnapshot(` + "it('renders page successfully', () => {}) + " + `) + }) + + test('creates a test for the index component', async () => { + expect( + tsFiles[ + path.normalize( + '/path/to/project/web/src/components/Post/Post/Post.test.tsx', + ) + ], + ).toMatchInlineSnapshot(` + "it('renders component successfully', () => {}) + " + `) + }) + + test('creates mocks for the index component', async () => { + expect( + tsFiles[ + path.normalize( + '/path/to/project/web/src/components/Post/Post/Post.mock.ts', + ) + ], + ).toMatchInlineSnapshot(` + "export const standard = () => ({ custom: '' }) + " + `) + }) + // SDL // (Including this in the test just to make sure we're testing at least one // api-side file) From 776518e6e758d79ccd5f00de03c58b778348a1b5 Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Sun, 29 Dec 2024 16:40:57 -0600 Subject: [PATCH 06/18] feat(scaffold): add mock templates and test files for new components --- .../commands/generate/scaffold/scaffold.js | 33 +++++ .../components/EditNameCell.mock.ts.template | 4 + .../EditNameCell.stories.tsx.template | 29 +++++ .../components/EditNameCell.test.tsx.template | 25 ++++ .../components/EditNameCell.tsx copy.template | 74 +++++++++++ .../components/Name.mock.ts.template | 4 + .../components/Name.stories.tsx.template | 26 ++++ .../components/Name.test.tsx.template | 15 +++ .../components/Name.tsx copy.template | 79 +++++++++++ .../components/NameCell.mock.ts.template | 4 + .../components/NameCell.stories.tsx.template | 29 +++++ .../components/NameCell.test.tsx.template | 25 ++++ .../components/NameCell.tsx copy.template | 32 +++++ .../components/NameForm.mock.ts.template | 4 + .../components/NameForm.stories.tsx.template | 26 ++++ .../components/NameForm.test.tsx.template | 14 ++ .../components/NameForm.tsx copy.template | 123 ++++++++++++++++++ .../components/Names.mock.ts.template | 4 + .../components/Names.stories.tsx.template | 26 ++++ .../components/Names.test.tsx copy.template | 26 ++++ .../components/Names.test.tsx.template | 15 +++ .../components/Names.tsx copy.template | 88 +++++++++++++ .../components/NamesCell.mock.ts.template | 4 + .../components/NamesCell.stories.tsx.template | 35 +++++ .../components/NamesCell.test.tsx.template | 30 +++++ .../components/NamesCell.tsx copy.template | 45 +++++++ .../components/NewName.mock.ts.template | 4 + .../components/NewName.stories.tsx.template | 26 ++++ .../components/NewName.test.tsx.template | 14 ++ .../components/NewName.tsx copy.template | 55 ++++++++ .../pages/EditNamePage.stories.tsx.template | 13 ++ .../pages/EditNamePage.test.tsx.template | 14 ++ .../pages/EditNamePage.tsx copy.template | 11 ++ .../pages/NamePage.stories.tsx.template | 13 ++ .../pages/NamePage.test.tsx.template | 14 ++ .../pages/NamePage.tsx copy.template | 11 ++ .../pages/NamesPage.stories.tsx.template | 13 ++ .../pages/NamesPage.test.tsx.template | 14 ++ .../pages/NamesPage.tsx copy.template | 7 + .../pages/NewNamePage.stories.tsx.template | 13 ++ .../pages/NewNamePage.test.tsx.template | 14 ++ .../pages/NewNamePage.tsx copy.template | 7 + 42 files changed, 1062 insertions(+) create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.mock.ts.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Name.mock.ts.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Name.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Name.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Name.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NameCell.mock.ts.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NameCell.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NameCell.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NameCell.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NameForm.mock.ts.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NameForm.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NameForm.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NameForm.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Names.mock.ts.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Names.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Names.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.mock.ts.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NewName.mock.ts.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NewName.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NewName.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NewName.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.tsx copy.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.stories.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.test.tsx.template create mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.tsx copy.template diff --git a/packages/cli/src/commands/generate/scaffold/scaffold.js b/packages/cli/src/commands/generate/scaffold/scaffold.js index c0ce366464cc..a2d631480e06 100644 --- a/packages/cli/src/commands/generate/scaffold/scaffold.js +++ b/packages/cli/src/commands/generate/scaffold/scaffold.js @@ -43,6 +43,7 @@ import { files as sdlFiles, builder as sdlBuilder } from '../sdl/sdl' import { files as serviceFiles, builder as serviceBuilder, + buildScenario, } from '../service/service' // note a better way to do this is in https://github.com/redwoodjs/redwood/pull/3783/files @@ -436,6 +437,7 @@ const modelRelatedVariables = (model) => { editableColumns, listFormattersImports, formattersImports, + relations, } } @@ -559,6 +561,36 @@ const pageFiles = async ( return fileList } +/** + * Builds mock data for a given model. + * + * @param {Object} model - The model object containing information about the model. + * @param {string} model.name - The name of the model. + * @param {Array} model.fields - The fields of the model. + * @param {boolean} model.fields[].isId - Indicates if the field is an ID field. + * @param {string} model.fields[].type - The type of the field. + * @returns {Promise>} A promise that resolves to an array of mock data objects. + */ +const buildMockData = async (model) => { + const singularName = pascalcase(singularize(model.name)) + const camelName = camelcase(singularName) + const scenario = await buildScenario(singularName) + const idType = getIdType(model) + const intMockIdValues = [42, 43, 44] + + const mockIdValues = + idType === 'String' + ? intMockIdValues.map((value) => `'${value}'`) + : intMockIdValues + + // this assumes scenario will only have two objects + return Object.entries(scenario[camelName]).map(([_key, value], index) => ({ + __typename: singularName, + id: mockIdValues[index], + ...value.data, + })) +} + const componentFiles = async ( name, pascalScaffoldPath = '', @@ -623,6 +655,7 @@ const componentFiles = async ( useClientDirective, ...templateStrings, ...modelRelatedVariables(model), + mockData: await buildMockData(model), }, ) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.mock.ts.template b/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.mock.ts.template new file mode 100644 index 000000000000..ceb5273831c9 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.mock.ts.template @@ -0,0 +1,4 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + ${camelName}: <%= JSON.stringify(mockData[0], null, 2) %> +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.stories.tsx.template new file mode 100644 index 000000000000..6d79f769ea0b --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.stories.tsx.template @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { Loading, Failure, Success } from './Edit${pascalName}Cell' +import { standard } from './Edit${pascalName}Cell.mock' + +const meta: Meta = { + title: 'Cells/Edit${pascalName}Cell', + tags: ['autodocs'] +} + +export default meta + +export const loading: StoryObj = { + render: () => { + return Loading ? : <> + }, +} + +export const failure: StoryObj = { + render: (args) => { + return Failure ? : <> + } +} + +export const success: StoryObj = { + render: (args) => { + return Success ? : <> + } +} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.test.tsx.template new file mode 100644 index 000000000000..ad5da441a20e --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.test.tsx.template @@ -0,0 +1,25 @@ +import { render } from '@redwoodjs/testing/web' + +import { Loading, Failure, Success } from './Edit${pascalName}Cell' +import { standard } from './Edit${pascalName}Cell.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('Edit${pascalName}Cell', () => { + it('renders loading successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders failure successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.tsx copy.template new file mode 100644 index 000000000000..227b079a1a06 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.tsx copy.template @@ -0,0 +1,74 @@ +${useClientDirective}import type { + Edit${singularPascalName}By${pascalIdName}, + Update${singularPascalName}Input, + Update${singularPascalName}MutationVariables +} from 'types/graphql' + +import { navigate, routes } from '@redwoodjs/router' +import type { + CellSuccessProps, + CellFailureProps, + TypedDocumentNode, +} from '@redwoodjs/web' +import { useMutation } from '@redwoodjs/web' +import { toast } from '@redwoodjs/web/toast' + +import ${singularPascalName}Form from '${importComponentNameForm}' + +export const QUERY: TypedDocumentNode = gql` + query Edit${singularPascalName}By${pascalIdName}($${idName}: ${idType}!) { + ${singularCamelName}: ${singularCamelName}(${idName}: $${idName}) {<% columns.forEach(column => { %> + <%= column.name %><% }) %> + } + } +` + +const UPDATE_${singularConstantName}_MUTATION: TypedDocumentNode< + Edit${singularPascalName}ById, + Update${singularPascalName}MutationVariables +> = gql` + mutation Update${singularPascalName}Mutation($${idName}: ${idType}!, $input: Update${singularPascalName}Input!) { + update${singularPascalName}(${idName}: $${idName}, input: $input) {<% columns.forEach(column => { %> + <%= column.name %><% }) %> + } + } +` + +export const Loading = () =>
Loading...
+ +export const Failure = ({ error }: CellFailureProps) => ( +
{error?.message}
+) + +export const Success = ({ ${singularCamelName} }: CellSuccessProps) => { + const [update${singularPascalName}, { loading, error }] = useMutation( + UPDATE_${singularConstantName}_MUTATION, + { + onCompleted: () => { + toast.success('${singularPascalName} updated') + navigate(routes.${pluralRouteName}()) + }, + onError: (error) => { + toast.error(error.message) + }, + } + ) + + const onSave = ( + input: Update${singularPascalName}Input, + id: Edit${singularPascalName}By${pascalIdName}['${singularCamelName}']['id'] + ) => { + update${singularPascalName}({ variables: { id, input } }) + } + + return ( +
+
+

Edit ${singularPascalName} {${singularCamelName}?.id}

+
+
+ <${singularPascalName}Form ${singularCamelName}={${singularCamelName}} onSave={onSave} error={error} loading={loading} /> +
+
+ ) +} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Name.mock.ts.template b/packages/cli/src/commands/generate/scaffold/templates/components/Name.mock.ts.template new file mode 100644 index 000000000000..ceb5273831c9 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/Name.mock.ts.template @@ -0,0 +1,4 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + ${camelName}: <%= JSON.stringify(mockData[0], null, 2) %> +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Name.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/Name.stories.tsx.template new file mode 100644 index 000000000000..5311ada81bbd --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/Name.stories.tsx.template @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import ${pascalName} from './${pascalName}' + +const meta: Meta = { + component: ${pascalName}, + tags: ['autodocs'] +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Name.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/Name.test.tsx.template new file mode 100644 index 000000000000..b8aaa1284276 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/Name.test.tsx.template @@ -0,0 +1,15 @@ +import { render } from '@redwoodjs/testing/web' + +import ${pascalName} from './${pascalName}' +import { standard } from './${pascalName}.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('${pascalName}', () => { + it('renders successfully', () => { + expect(() => { + render(<${pascalName} ${camelName}={standard().${camelName}} />) + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Name.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/Name.tsx copy.template new file mode 100644 index 000000000000..f95e5e04656a --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/Name.tsx copy.template @@ -0,0 +1,79 @@ +import type { Delete${singularPascalName}Mutation, Delete${singularPascalName}MutationVariables, Find${singularPascalName}By${pascalIdName} } from 'types/graphql' + +import { Link, routes, navigate } from '@redwoodjs/router' +import { useMutation } from '@redwoodjs/web' +import type { TypedDocumentNode } from '@redwoodjs/web' +import { toast } from '@redwoodjs/web/toast' + +import { ${formattersImports} } from 'src/lib/formatters' + +const DELETE_${singularConstantName}_MUTATION: TypedDocumentNode = gql` + mutation Delete${singularPascalName}Mutation($${idName}: ${idType}!) { + delete${singularPascalName}(${idName}: $${idName}) { + ${idName} + } + } +` + +interface Props { + ${singularCamelName}: NonNullable +} + +const ${singularPascalName} = ({ ${singularCamelName} }: Props) => { + const [delete${singularPascalName}] = useMutation(DELETE_${singularConstantName}_MUTATION, { + onCompleted: () => { + toast.success('${singularPascalName} deleted') + navigate(routes.${pluralRouteName}()) + }, + onError: (error) => { + toast.error(error.message) + }, + }) + + const onDeleteClick = (${idName}: Delete${singularPascalName}MutationVariables['${idName}']) => { + if (confirm('Are you sure you want to delete ${singularCamelName} ' + ${idName} + '?')) { + delete${singularPascalName}({ variables: { ${idName} } }) + } + } + + return ( + <> +
+
+

+ ${singularPascalName} {${singularCamelName}.${idName}} Detail +

+
+ + + <% columns.forEach(column => { %> + <% + if (column.displayFunction) { %> + <% + } else { %> + <% + } %> + <% }) %> + +
<%= column.label %>{${column.displayFunction}(${singularCamelName}.${column.name})}{${singularCamelName}.${column.name}}
+
+ + + ) +} + +export default ${singularPascalName} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.mock.ts.template b/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.mock.ts.template new file mode 100644 index 000000000000..245bdfc6f2f9 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.mock.ts.template @@ -0,0 +1,4 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + ${camelName}: <%= JSON.stringify(mockData[0], null, 2) %> + }) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.stories.tsx.template new file mode 100644 index 000000000000..4a4e345f4869 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.stories.tsx.template @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { Loading, Failure, Success } from './${pascalName}Cell' +import { standard } from './${pascalName}Cell.mock' + +const meta: Meta = { + title: 'Cells/${pascalName}Cell', + tags: ['autodocs'] +} + +export default meta + +export const loading: StoryObj = { + render: () => { + return Loading ? : <> + }, +} + +export const failure: StoryObj = { + render: (args) => { + return Failure ? : <> + } +} + +export const success: StoryObj = { + render: (args) => { + return Success ? : <> + } +} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.test.tsx.template new file mode 100644 index 000000000000..56b514100535 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.test.tsx.template @@ -0,0 +1,25 @@ +import { render } from '@redwoodjs/testing/web' + +import { Loading, Failure, Success } from './${pascalName}Cell' +import { standard } from './${pascalName}Cell.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('${pascalName}Cell', () => { + it('renders loading successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders failure successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.tsx copy.template new file mode 100644 index 000000000000..d804292f4fd0 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.tsx copy.template @@ -0,0 +1,32 @@ +${useClientDirective}import type { Find${singularPascalName}By${pascalIdName}, Find${singularPascalName}By${pascalIdName}Variables } from 'types/graphql' + +import type { + CellSuccessProps, + CellFailureProps, + TypedDocumentNode, +} from '@redwoodjs/web' + +import ${singularPascalName} from '${importComponentName}' + +export const QUERY: TypedDocumentNode< + Find${singularPascalName}By${pascalIdName}, + Find${singularPascalName}By${pascalIdName}Variables +> = gql` + query Find${singularPascalName}By${pascalIdName}($${idName}: ${idType}!) { + ${singularCamelName}: ${singularCamelName}(${idName}: $${idName}) {<% columns.forEach(column => { %> + <%= column.name %><% }) %> + } + } +` + +export const Loading = () =>
Loading...
+ +export const Empty = () =>
${singularPascalName} not found
+ +export const Failure = ({ error }: CellFailureProps) => ( +
{error?.message}
+) + +export const Success = ({ ${singularCamelName} }: CellSuccessProps) => { + return <${singularPascalName} ${singularCamelName}={${singularCamelName}} /> +} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.mock.ts.template b/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.mock.ts.template new file mode 100644 index 000000000000..245bdfc6f2f9 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.mock.ts.template @@ -0,0 +1,4 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + ${camelName}: <%= JSON.stringify(mockData[0], null, 2) %> + }) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.stories.tsx.template new file mode 100644 index 000000000000..220d95f8a0f9 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.stories.tsx.template @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import ${pascalName}Form from './${pascalName}Form' + +const meta: Meta = { + component: ${pascalName}Form, + tags: ['autodocs'] +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.test.tsx.template new file mode 100644 index 000000000000..d24ad720a1bb --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.test.tsx.template @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import ${pascalName}Form from './${pascalName}Form' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('${pascalName}Form', () => { + it('renders successfully', () => { + expect(() => { + render(<${pascalName}Form />) + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.tsx copy.template new file mode 100644 index 000000000000..f8382745872b --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.tsx copy.template @@ -0,0 +1,123 @@ +import type { Edit${singularPascalName}By${pascalIdName}, Update${singularPascalName}Input } from 'types/graphql' + +import type { RWGqlError } from '@redwoodjs/forms' +import { + Form, + FormError, + FieldError, + Label, + ${fieldsToImport.join(',\n ')}, + Submit, +} from '@redwoodjs/forms' + +<% if (fieldsToImport.includes('DatetimeLocalField')) { %> +const formatDatetime = (value) => { + if (value) { + return value.replace(/:\d{2}\.\d{3}\w/, '') + } +} +<% } %> + +type Form${singularPascalName} = NonNullable + +interface ${singularPascalName}FormProps { + ${singularCamelName}?: Edit${singularPascalName}By${pascalIdName}['${singularCamelName}'] + onSave: (data: Update${singularPascalName}Input, ${idName}?: Form${singularPascalName}['${idName}']) => void + error: RWGqlError + loading: boolean +} + +const ${singularPascalName}Form = (props: ${singularPascalName}FormProps) => { + const onSubmit = (data: Form${singularPascalName}) => { + <% editableColumns.forEach(column => { %> + <% if (column.isEnum && !column.isList && !column.isRequired) { %> + if (data.${column.name} === '') { + data.${column.name} = null + } + <% } %> + <% if (column.isEnum && column.isList) { %> + if (data.${column.name}) { + data.${column.name} = data.${column.name}.filter((value) => !!value) + } + <% } %> + <% }) %> + props.onSave(data, props?.${singularCamelName}?.${idName}) + } + + return ( +
+ onSubmit={onSubmit} error={props.error}> + + <% editableColumns.forEach(column => { %> + + <% if (column.isEnum) { %> + <% if (!column.isRequired) { %> +
+ <${column.component} + ${idName}="${singularCamelName}-${column.name}-none" + name="${column.name}" + defaultValue="" + ${column.defaultProp}={!props.${singularCamelName}?.${column.name}} + className="rw-input" + errorClassName="rw-input rw-input-error" + /> +
+ None +
+
+ <% } %> + <% column.values?.forEach((value, i) => { + const columnComponentName = column.isList ? `${column.name}[${i}]` : column.name + %> +
+ <${column.component} + ${idName}="${singularCamelName}-${column.name}-${i}" + name="${columnComponentName}" + defaultValue="${value.name}" + ${column.defaultProp}={props.${singularCamelName}?.${column.name}?.includes('${value.name}')} + className="rw-input" + errorClassName="rw-input rw-input-error" + /> +
+ ${value.name.replace('_', ' ').toLowerCase().replace(/\b\w/g, l => l.toUpperCase())} +
+
+ <% }) %> + <% } else { %> + <${column.component} + name="${column.name}" + ${column.defaultProp}={${column.deserializeFunction && column.deserializeFunction + '('}props.${singularCamelName}?.<%= column.name %>${column.deserializeFunction && ')'}} + className="rw-input" + errorClassName="rw-input rw-input-error" + <%= !column.validation ? '' : `validation=${column.validation}` %> + <%= column.isRelationalField && !column.isRequired ? `emptyAs={'undefined'}` : '' %> + /> + <% } %> + + +<% }) %> +
+ + Save + +
+ +
+ ) +} + +export default ${singularPascalName}Form diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Names.mock.ts.template b/packages/cli/src/commands/generate/scaffold/templates/components/Names.mock.ts.template new file mode 100644 index 000000000000..4253b27e8e90 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/Names.mock.ts.template @@ -0,0 +1,4 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + ${pluralCamelName}: <%= JSON.stringify(mockData, null, 2) %>, + }) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Names.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/Names.stories.tsx.template new file mode 100644 index 000000000000..ff6ef5e9e697 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/Names.stories.tsx.template @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import ${pluralPascalName} from './${pluralPascalName}' + +const meta: Meta = { + component: ${pluralPascalName}, + tags: ['autodocs'] +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx copy.template new file mode 100644 index 000000000000..ff6ef5e9e697 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx copy.template @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import ${pluralPascalName} from './${pluralPascalName}' + +const meta: Meta = { + component: ${pluralPascalName}, + tags: ['autodocs'] +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx.template new file mode 100644 index 000000000000..f06bb23c3320 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx.template @@ -0,0 +1,15 @@ +import { render } from '@redwoodjs/testing/web' + +import ${pluralPascalName} from './${pluralPascalName}' +import { standard } from './${pluralPascalName}.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('${pluralPascalName}', () => { + it('renders successfully', () => { + expect(() => { + render(<${pluralPascalName} ${pluralCamelName}={standard().${pluralCamelName}} />) + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Names.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/Names.tsx copy.template new file mode 100644 index 000000000000..eb23f726cd7c --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/Names.tsx copy.template @@ -0,0 +1,88 @@ +import type { Delete${singularPascalName}Mutation, Delete${singularPascalName}MutationVariables, Find${pluralPascalName} } from 'types/graphql' + +import { Link, routes } from '@redwoodjs/router' +import { useMutation } from '@redwoodjs/web' +import type { TypedDocumentNode } from '@redwoodjs/web' +import { toast } from '@redwoodjs/web/toast' + +import { QUERY } from '${importComponentNamesCell}' +import { ${listFormattersImports} } from 'src/lib/formatters' + + +const DELETE_${singularConstantName}_MUTATION: TypedDocumentNode = gql` + mutation Delete${singularPascalName}Mutation($${idName}: ${idType}!) { + delete${singularPascalName}(${idName}: $${idName}) { + ${idName} + } + } +` + +const ${pluralPascalName}List = ({ ${pluralCamelName} }: Find${pluralPascalName}) => { + const [delete${singularPascalName}] = useMutation(DELETE_${singularConstantName}_MUTATION, { + onCompleted: () => { + toast.success('${singularPascalName} deleted') + }, + onError: (error) => { + toast.error(error.message) + }, + // This refetches the query on the list page. Read more about other ways to + // update the cache over here: + // https://www.apollographql.com/docs/react/data/mutations/#making-all-other-cache-updates + refetchQueries: [{ query: QUERY }], + awaitRefetchQueries: true, + }) + + const onDeleteClick = (${idName}: Delete${singularPascalName}MutationVariables['${idName}']) => { + if (confirm('Are you sure you want to delete ${singularCamelName} ' + ${idName} + '?')) { + delete${singularPascalName}({ variables: { ${idName} } }) + } + } + + return ( +
+ + + <% columns.forEach(column => { %> + <% }) %> + + + + + {${pluralCamelName}.map((${singularCamelName}) => ( + <% columns.forEach(column => { %> + <% }) %> + + + ))} + +
${column.label} 
{${column.listDisplayFunction}(${singularCamelName}.${column.name})} + +
+
+ ) +} + +export default ${pluralPascalName}List diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.mock.ts.template b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.mock.ts.template new file mode 100644 index 000000000000..4253b27e8e90 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.mock.ts.template @@ -0,0 +1,4 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + ${pluralCamelName}: <%= JSON.stringify(mockData, null, 2) %>, + }) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.stories.tsx.template new file mode 100644 index 000000000000..8e07ab5cd1cd --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.stories.tsx.template @@ -0,0 +1,35 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { Loading, Empty, Failure, Success } from './${pascalName}sCell' +import { standard } from './${pascalName}sCell.mock' + +const meta: Meta = { + title: 'Cells/${pascalName}sCell', + tags: ['autodocs'] +} + +export default meta + +export const loading: StoryObj = { + render: () => { + return Loading ? : <> + }, +} + +export const failure: StoryObj = { + render: (args) => { + return Failure ? : <> + } +} + +export const empty: StoryObj = { + render: (args) => { + return Empty ? : <> + } +} + +export const success: StoryObj = { + render: (args) => { + return Success ? : <> + } +} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.test.tsx.template new file mode 100644 index 000000000000..01b817869aab --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.test.tsx.template @@ -0,0 +1,30 @@ +import { render } from '@redwoodjs/testing/web' + +import { Loading, Failure, Empty, Success } from './${pluralPascalName}Cell' +import { standard } from './${pluralPascalName}Cell.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('${pluralPascalName}Cell', () => { + it('renders loading successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders failure successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders empty successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx copy.template new file mode 100644 index 000000000000..23c15e94bdae --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx copy.template @@ -0,0 +1,45 @@ +${useClientDirective}import type { Find${pluralPascalName}, Find${pluralPascalName}Variables } from 'types/graphql' + +import { Link, routes } from '@redwoodjs/router' +import type { + CellSuccessProps, + CellFailureProps, + TypedDocumentNode, +} from '@redwoodjs/web' + +import ${pluralPascalName} from '${importComponentNames}' + +export const QUERY: TypedDocumentNode< + Find${pluralPascalName}, + Find${pluralPascalName}Variables +> = gql` + query Find${pluralPascalName} { + ${pluralCamelName} {<% columns.forEach(column => { %> + <%= column.name %><% }) %> + } + } +` + +export const Loading = () =>
Loading...
+ +export const Empty = () => { + return ( +
+ No ${pluralCamelName} yet.{' '} + + Create one? + +
+ ) +} + +export const Failure = ({ error }: CellFailureProps) => ( +
{error?.message}
+) + +export const Success = ({ ${pluralCamelName} }: CellSuccessProps) => { + return <${pluralPascalName} ${pluralCamelName}={${pluralCamelName}} /> +} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NewName.mock.ts.template b/packages/cli/src/commands/generate/scaffold/templates/components/NewName.mock.ts.template new file mode 100644 index 000000000000..245bdfc6f2f9 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NewName.mock.ts.template @@ -0,0 +1,4 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + ${camelName}: <%= JSON.stringify(mockData[0], null, 2) %> + }) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NewName.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/NewName.stories.tsx.template new file mode 100644 index 000000000000..a3ccd6e603ae --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NewName.stories.tsx.template @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import New${pascalName} from './New${pascalName}' + +const meta: Meta = { + component: New${pascalName}, + tags: ['autodocs'] +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NewName.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/NewName.test.tsx.template new file mode 100644 index 000000000000..01a8f809b2a1 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NewName.test.tsx.template @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import New${pascalName} from './New${pascalName}' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('New${pascalName}', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NewName.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/NewName.tsx copy.template new file mode 100644 index 000000000000..36fe7b553287 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NewName.tsx copy.template @@ -0,0 +1,55 @@ +${useClientDirective}import type { + Create${singularPascalName}Mutation, + Create${singularPascalName}Input, + Create${singularPascalName}MutationVariables +} from 'types/graphql' + +import { navigate, routes } from '@redwoodjs/router' +import { useMutation } from '@redwoodjs/web' +import type { TypedDocumentNode } from '@redwoodjs/web' +import { toast } from '@redwoodjs/web/toast' + +import ${singularPascalName}Form from '${importComponentNameForm}' + +const CREATE_${singularConstantName}_MUTATION: TypedDocumentNode< + Create${singularPascalName}Mutation, + Create${singularPascalName}MutationVariables +> = gql` + mutation Create${singularPascalName}Mutation($input: Create${singularPascalName}Input!) { + create${singularPascalName}(input: $input) { + ${idName} + } + } +` + +const New${singularPascalName} = () => { + const [create${singularPascalName}, { loading, error }] = useMutation( + CREATE_${singularConstantName}_MUTATION, + { + onCompleted: () => { + toast.success('${singularPascalName} created') + navigate(routes.${pluralRouteName}()) + }, + onError: (error) => { + toast.error(error.message) + }, + } + ) + + const onSave = (input: Create${singularPascalName}Input) => { + create${singularPascalName}({ variables: { input } }) + } + + return ( +
+
+

New ${singularPascalName}

+
+
+ <${singularPascalName}Form onSave={onSave} loading={loading} error={error} /> +
+
+ ) +} + +export default New${singularPascalName} diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.stories.tsx.template new file mode 100644 index 000000000000..f3bc948f67a7 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.stories.tsx.template @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import Edit${pascalName}Page from './Edit${pascalName}Page' + +const meta: Meta = { + component: Edit${pascalName}Page, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.test.tsx.template new file mode 100644 index 000000000000..0079b96d0840 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.test.tsx.template @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import Edit${pascalName}Page from './Edit${pascalName}Page' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('Edit${pascalName}Page', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.tsx copy.template new file mode 100644 index 000000000000..305b2a0dee24 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.tsx copy.template @@ -0,0 +1,11 @@ +import Edit${singularPascalName}Cell from '${importComponentEditNameCell}' + +type ${pascalName}PageProps = { + ${idName}: ${idTsType} +} + +const Edit${singularPascalName}Page = ({ ${idName} }: ${pascalName}PageProps) => { + return +} + +export default Edit${singularPascalName}Page diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.stories.tsx.template new file mode 100644 index 000000000000..69427f309a36 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.stories.tsx.template @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import ${pascalName}Page from './${pascalName}Page' + +const meta: Meta = { + component: ${pascalName}Page, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.test.tsx.template new file mode 100644 index 000000000000..40375b95b3f3 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.test.tsx.template @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import ${pascalName}Page from './${pascalName}Page' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('${pascalName}Page', () => { + it('renders successfully', () => { + expect(() => { + render(<${pascalName}Page ${idName}="42" />) + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.tsx copy.template new file mode 100644 index 000000000000..c1a94d5f478c --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.tsx copy.template @@ -0,0 +1,11 @@ +import ${singularPascalName}Cell from '${importComponentNameCell}' + +type ${pascalName}PageProps = { + ${idName}: ${idTsType} +} + +const ${singularPascalName}Page = ({ ${idName} }: ${pascalName}PageProps) => { + return <${singularPascalName}Cell ${idName}={${idName}} /> +} + +export default ${singularPascalName}Page diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.stories.tsx.template new file mode 100644 index 000000000000..5b28d1a2b6d7 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.stories.tsx.template @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import ${pluralPascalName}Page from './${pluralPascalName}Page' + +const meta: Meta = { + component: ${pluralPascalName}Page, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.test.tsx.template new file mode 100644 index 000000000000..522857f384e1 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.test.tsx.template @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import ${pluralPascalName}Page from './${pluralPascalName}Page' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('${pluralPascalName}Page', () => { + it('renders successfully', () => { + expect(() => { + render(<${pluralPascalName}Page />) + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.tsx copy.template new file mode 100644 index 000000000000..f4c5a5e541b2 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.tsx copy.template @@ -0,0 +1,7 @@ +import ${pluralPascalName}Cell from '${importComponentNamesCell}' + +const ${pluralPascalName}Page = () => { + return <${pluralPascalName}Cell /> +} + +export default ${pluralPascalName}Page diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.stories.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.stories.tsx.template new file mode 100644 index 000000000000..edb8eb407c2e --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.stories.tsx.template @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import New${pascalName}Page from './New${pascalName}Page' + +const meta: Meta = { + component: New${pascalName}Page, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.test.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.test.tsx.template new file mode 100644 index 000000000000..c3cb8c18d323 --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.test.tsx.template @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import New${pascalName}Page from './New${pascalName}Page' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('New${pascalName}Page', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.tsx copy.template new file mode 100644 index 000000000000..afe1c6d178bb --- /dev/null +++ b/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.tsx copy.template @@ -0,0 +1,7 @@ +import New${singularPascalName} from '${importComponentNewName}' + +const New${singularPascalName}Page = () => { + return +} + +export default New${singularPascalName}Page From 51f83ad776253d0e22cf92a628ccaff1ce12d08b Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Mon, 30 Dec 2024 09:20:48 -0600 Subject: [PATCH 07/18] fix(scaffold): remove duplicated template files --- .../components/EditNameCell.tsx copy.template | 74 ----------- .../components/Name.tsx copy.template | 79 ----------- .../components/NameCell.tsx copy.template | 32 ----- .../components/NameForm.tsx copy.template | 123 ------------------ .../components/Names.test.tsx copy.template | 26 ---- .../components/Names.tsx copy.template | 88 ------------- .../components/NamesCell.tsx copy.template | 45 ------- .../components/NewName.tsx copy.template | 55 -------- .../pages/EditNamePage.tsx copy.template | 11 -- .../pages/NamePage.tsx copy.template | 11 -- .../pages/NamesPage.tsx copy.template | 7 - .../pages/NewNamePage.tsx copy.template | 7 - 12 files changed, 558 deletions(-) delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Name.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NameCell.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NameForm.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/Names.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/components/NewName.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.tsx copy.template delete mode 100644 packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.tsx copy.template diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.tsx copy.template deleted file mode 100644 index 227b079a1a06..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/components/EditNameCell.tsx copy.template +++ /dev/null @@ -1,74 +0,0 @@ -${useClientDirective}import type { - Edit${singularPascalName}By${pascalIdName}, - Update${singularPascalName}Input, - Update${singularPascalName}MutationVariables -} from 'types/graphql' - -import { navigate, routes } from '@redwoodjs/router' -import type { - CellSuccessProps, - CellFailureProps, - TypedDocumentNode, -} from '@redwoodjs/web' -import { useMutation } from '@redwoodjs/web' -import { toast } from '@redwoodjs/web/toast' - -import ${singularPascalName}Form from '${importComponentNameForm}' - -export const QUERY: TypedDocumentNode = gql` - query Edit${singularPascalName}By${pascalIdName}($${idName}: ${idType}!) { - ${singularCamelName}: ${singularCamelName}(${idName}: $${idName}) {<% columns.forEach(column => { %> - <%= column.name %><% }) %> - } - } -` - -const UPDATE_${singularConstantName}_MUTATION: TypedDocumentNode< - Edit${singularPascalName}ById, - Update${singularPascalName}MutationVariables -> = gql` - mutation Update${singularPascalName}Mutation($${idName}: ${idType}!, $input: Update${singularPascalName}Input!) { - update${singularPascalName}(${idName}: $${idName}, input: $input) {<% columns.forEach(column => { %> - <%= column.name %><% }) %> - } - } -` - -export const Loading = () =>
Loading...
- -export const Failure = ({ error }: CellFailureProps) => ( -
{error?.message}
-) - -export const Success = ({ ${singularCamelName} }: CellSuccessProps) => { - const [update${singularPascalName}, { loading, error }] = useMutation( - UPDATE_${singularConstantName}_MUTATION, - { - onCompleted: () => { - toast.success('${singularPascalName} updated') - navigate(routes.${pluralRouteName}()) - }, - onError: (error) => { - toast.error(error.message) - }, - } - ) - - const onSave = ( - input: Update${singularPascalName}Input, - id: Edit${singularPascalName}By${pascalIdName}['${singularCamelName}']['id'] - ) => { - update${singularPascalName}({ variables: { id, input } }) - } - - return ( -
-
-

Edit ${singularPascalName} {${singularCamelName}?.id}

-
-
- <${singularPascalName}Form ${singularCamelName}={${singularCamelName}} onSave={onSave} error={error} loading={loading} /> -
-
- ) -} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Name.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/Name.tsx copy.template deleted file mode 100644 index f95e5e04656a..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/components/Name.tsx copy.template +++ /dev/null @@ -1,79 +0,0 @@ -import type { Delete${singularPascalName}Mutation, Delete${singularPascalName}MutationVariables, Find${singularPascalName}By${pascalIdName} } from 'types/graphql' - -import { Link, routes, navigate } from '@redwoodjs/router' -import { useMutation } from '@redwoodjs/web' -import type { TypedDocumentNode } from '@redwoodjs/web' -import { toast } from '@redwoodjs/web/toast' - -import { ${formattersImports} } from 'src/lib/formatters' - -const DELETE_${singularConstantName}_MUTATION: TypedDocumentNode = gql` - mutation Delete${singularPascalName}Mutation($${idName}: ${idType}!) { - delete${singularPascalName}(${idName}: $${idName}) { - ${idName} - } - } -` - -interface Props { - ${singularCamelName}: NonNullable -} - -const ${singularPascalName} = ({ ${singularCamelName} }: Props) => { - const [delete${singularPascalName}] = useMutation(DELETE_${singularConstantName}_MUTATION, { - onCompleted: () => { - toast.success('${singularPascalName} deleted') - navigate(routes.${pluralRouteName}()) - }, - onError: (error) => { - toast.error(error.message) - }, - }) - - const onDeleteClick = (${idName}: Delete${singularPascalName}MutationVariables['${idName}']) => { - if (confirm('Are you sure you want to delete ${singularCamelName} ' + ${idName} + '?')) { - delete${singularPascalName}({ variables: { ${idName} } }) - } - } - - return ( - <> -
-
-

- ${singularPascalName} {${singularCamelName}.${idName}} Detail -

-
- - - <% columns.forEach(column => { %> - <% - if (column.displayFunction) { %> - <% - } else { %> - <% - } %> - <% }) %> - -
<%= column.label %>{${column.displayFunction}(${singularCamelName}.${column.name})}{${singularCamelName}.${column.name}}
-
- - - ) -} - -export default ${singularPascalName} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.tsx copy.template deleted file mode 100644 index d804292f4fd0..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/components/NameCell.tsx copy.template +++ /dev/null @@ -1,32 +0,0 @@ -${useClientDirective}import type { Find${singularPascalName}By${pascalIdName}, Find${singularPascalName}By${pascalIdName}Variables } from 'types/graphql' - -import type { - CellSuccessProps, - CellFailureProps, - TypedDocumentNode, -} from '@redwoodjs/web' - -import ${singularPascalName} from '${importComponentName}' - -export const QUERY: TypedDocumentNode< - Find${singularPascalName}By${pascalIdName}, - Find${singularPascalName}By${pascalIdName}Variables -> = gql` - query Find${singularPascalName}By${pascalIdName}($${idName}: ${idType}!) { - ${singularCamelName}: ${singularCamelName}(${idName}: $${idName}) {<% columns.forEach(column => { %> - <%= column.name %><% }) %> - } - } -` - -export const Loading = () =>
Loading...
- -export const Empty = () =>
${singularPascalName} not found
- -export const Failure = ({ error }: CellFailureProps) => ( -
{error?.message}
-) - -export const Success = ({ ${singularCamelName} }: CellSuccessProps) => { - return <${singularPascalName} ${singularCamelName}={${singularCamelName}} /> -} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.tsx copy.template deleted file mode 100644 index f8382745872b..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/components/NameForm.tsx copy.template +++ /dev/null @@ -1,123 +0,0 @@ -import type { Edit${singularPascalName}By${pascalIdName}, Update${singularPascalName}Input } from 'types/graphql' - -import type { RWGqlError } from '@redwoodjs/forms' -import { - Form, - FormError, - FieldError, - Label, - ${fieldsToImport.join(',\n ')}, - Submit, -} from '@redwoodjs/forms' - -<% if (fieldsToImport.includes('DatetimeLocalField')) { %> -const formatDatetime = (value) => { - if (value) { - return value.replace(/:\d{2}\.\d{3}\w/, '') - } -} -<% } %> - -type Form${singularPascalName} = NonNullable - -interface ${singularPascalName}FormProps { - ${singularCamelName}?: Edit${singularPascalName}By${pascalIdName}['${singularCamelName}'] - onSave: (data: Update${singularPascalName}Input, ${idName}?: Form${singularPascalName}['${idName}']) => void - error: RWGqlError - loading: boolean -} - -const ${singularPascalName}Form = (props: ${singularPascalName}FormProps) => { - const onSubmit = (data: Form${singularPascalName}) => { - <% editableColumns.forEach(column => { %> - <% if (column.isEnum && !column.isList && !column.isRequired) { %> - if (data.${column.name} === '') { - data.${column.name} = null - } - <% } %> - <% if (column.isEnum && column.isList) { %> - if (data.${column.name}) { - data.${column.name} = data.${column.name}.filter((value) => !!value) - } - <% } %> - <% }) %> - props.onSave(data, props?.${singularCamelName}?.${idName}) - } - - return ( -
- onSubmit={onSubmit} error={props.error}> - - <% editableColumns.forEach(column => { %> - - <% if (column.isEnum) { %> - <% if (!column.isRequired) { %> -
- <${column.component} - ${idName}="${singularCamelName}-${column.name}-none" - name="${column.name}" - defaultValue="" - ${column.defaultProp}={!props.${singularCamelName}?.${column.name}} - className="rw-input" - errorClassName="rw-input rw-input-error" - /> -
- None -
-
- <% } %> - <% column.values?.forEach((value, i) => { - const columnComponentName = column.isList ? `${column.name}[${i}]` : column.name - %> -
- <${column.component} - ${idName}="${singularCamelName}-${column.name}-${i}" - name="${columnComponentName}" - defaultValue="${value.name}" - ${column.defaultProp}={props.${singularCamelName}?.${column.name}?.includes('${value.name}')} - className="rw-input" - errorClassName="rw-input rw-input-error" - /> -
- ${value.name.replace('_', ' ').toLowerCase().replace(/\b\w/g, l => l.toUpperCase())} -
-
- <% }) %> - <% } else { %> - <${column.component} - name="${column.name}" - ${column.defaultProp}={${column.deserializeFunction && column.deserializeFunction + '('}props.${singularCamelName}?.<%= column.name %>${column.deserializeFunction && ')'}} - className="rw-input" - errorClassName="rw-input rw-input-error" - <%= !column.validation ? '' : `validation=${column.validation}` %> - <%= column.isRelationalField && !column.isRequired ? `emptyAs={'undefined'}` : '' %> - /> - <% } %> - - -<% }) %> -
- - Save - -
- -
- ) -} - -export default ${singularPascalName}Form diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx copy.template deleted file mode 100644 index ff6ef5e9e697..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/components/Names.test.tsx copy.template +++ /dev/null @@ -1,26 +0,0 @@ -// Pass props to your component by passing an `args` object to your story -// -// ```tsx -// export const Primary: Story = { -// args: { -// propName: propValue -// } -// } -// ``` -// -// See https://storybook.js.org/docs/react/writing-stories/args. - -import type { Meta, StoryObj } from '@storybook/react' - -import ${pluralPascalName} from './${pluralPascalName}' - -const meta: Meta = { - component: ${pluralPascalName}, - tags: ['autodocs'] -} - -export default meta - -type Story = StoryObj - -export const Primary: Story = {} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/Names.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/Names.tsx copy.template deleted file mode 100644 index eb23f726cd7c..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/components/Names.tsx copy.template +++ /dev/null @@ -1,88 +0,0 @@ -import type { Delete${singularPascalName}Mutation, Delete${singularPascalName}MutationVariables, Find${pluralPascalName} } from 'types/graphql' - -import { Link, routes } from '@redwoodjs/router' -import { useMutation } from '@redwoodjs/web' -import type { TypedDocumentNode } from '@redwoodjs/web' -import { toast } from '@redwoodjs/web/toast' - -import { QUERY } from '${importComponentNamesCell}' -import { ${listFormattersImports} } from 'src/lib/formatters' - - -const DELETE_${singularConstantName}_MUTATION: TypedDocumentNode = gql` - mutation Delete${singularPascalName}Mutation($${idName}: ${idType}!) { - delete${singularPascalName}(${idName}: $${idName}) { - ${idName} - } - } -` - -const ${pluralPascalName}List = ({ ${pluralCamelName} }: Find${pluralPascalName}) => { - const [delete${singularPascalName}] = useMutation(DELETE_${singularConstantName}_MUTATION, { - onCompleted: () => { - toast.success('${singularPascalName} deleted') - }, - onError: (error) => { - toast.error(error.message) - }, - // This refetches the query on the list page. Read more about other ways to - // update the cache over here: - // https://www.apollographql.com/docs/react/data/mutations/#making-all-other-cache-updates - refetchQueries: [{ query: QUERY }], - awaitRefetchQueries: true, - }) - - const onDeleteClick = (${idName}: Delete${singularPascalName}MutationVariables['${idName}']) => { - if (confirm('Are you sure you want to delete ${singularCamelName} ' + ${idName} + '?')) { - delete${singularPascalName}({ variables: { ${idName} } }) - } - } - - return ( -
- - - <% columns.forEach(column => { %> - <% }) %> - - - - - {${pluralCamelName}.map((${singularCamelName}) => ( - <% columns.forEach(column => { %> - <% }) %> - - - ))} - -
${column.label} 
{${column.listDisplayFunction}(${singularCamelName}.${column.name})} - -
-
- ) -} - -export default ${pluralPascalName}List diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx copy.template deleted file mode 100644 index 23c15e94bdae..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx copy.template +++ /dev/null @@ -1,45 +0,0 @@ -${useClientDirective}import type { Find${pluralPascalName}, Find${pluralPascalName}Variables } from 'types/graphql' - -import { Link, routes } from '@redwoodjs/router' -import type { - CellSuccessProps, - CellFailureProps, - TypedDocumentNode, -} from '@redwoodjs/web' - -import ${pluralPascalName} from '${importComponentNames}' - -export const QUERY: TypedDocumentNode< - Find${pluralPascalName}, - Find${pluralPascalName}Variables -> = gql` - query Find${pluralPascalName} { - ${pluralCamelName} {<% columns.forEach(column => { %> - <%= column.name %><% }) %> - } - } -` - -export const Loading = () =>
Loading...
- -export const Empty = () => { - return ( -
- No ${pluralCamelName} yet.{' '} - - Create one? - -
- ) -} - -export const Failure = ({ error }: CellFailureProps) => ( -
{error?.message}
-) - -export const Success = ({ ${pluralCamelName} }: CellSuccessProps) => { - return <${pluralPascalName} ${pluralCamelName}={${pluralCamelName}} /> -} diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NewName.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/components/NewName.tsx copy.template deleted file mode 100644 index 36fe7b553287..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/components/NewName.tsx copy.template +++ /dev/null @@ -1,55 +0,0 @@ -${useClientDirective}import type { - Create${singularPascalName}Mutation, - Create${singularPascalName}Input, - Create${singularPascalName}MutationVariables -} from 'types/graphql' - -import { navigate, routes } from '@redwoodjs/router' -import { useMutation } from '@redwoodjs/web' -import type { TypedDocumentNode } from '@redwoodjs/web' -import { toast } from '@redwoodjs/web/toast' - -import ${singularPascalName}Form from '${importComponentNameForm}' - -const CREATE_${singularConstantName}_MUTATION: TypedDocumentNode< - Create${singularPascalName}Mutation, - Create${singularPascalName}MutationVariables -> = gql` - mutation Create${singularPascalName}Mutation($input: Create${singularPascalName}Input!) { - create${singularPascalName}(input: $input) { - ${idName} - } - } -` - -const New${singularPascalName} = () => { - const [create${singularPascalName}, { loading, error }] = useMutation( - CREATE_${singularConstantName}_MUTATION, - { - onCompleted: () => { - toast.success('${singularPascalName} created') - navigate(routes.${pluralRouteName}()) - }, - onError: (error) => { - toast.error(error.message) - }, - } - ) - - const onSave = (input: Create${singularPascalName}Input) => { - create${singularPascalName}({ variables: { input } }) - } - - return ( -
-
-

New ${singularPascalName}

-
-
- <${singularPascalName}Form onSave={onSave} loading={loading} error={error} /> -
-
- ) -} - -export default New${singularPascalName} diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.tsx copy.template deleted file mode 100644 index 305b2a0dee24..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/pages/EditNamePage.tsx copy.template +++ /dev/null @@ -1,11 +0,0 @@ -import Edit${singularPascalName}Cell from '${importComponentEditNameCell}' - -type ${pascalName}PageProps = { - ${idName}: ${idTsType} -} - -const Edit${singularPascalName}Page = ({ ${idName} }: ${pascalName}PageProps) => { - return -} - -export default Edit${singularPascalName}Page diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.tsx copy.template deleted file mode 100644 index c1a94d5f478c..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/pages/NamePage.tsx copy.template +++ /dev/null @@ -1,11 +0,0 @@ -import ${singularPascalName}Cell from '${importComponentNameCell}' - -type ${pascalName}PageProps = { - ${idName}: ${idTsType} -} - -const ${singularPascalName}Page = ({ ${idName} }: ${pascalName}PageProps) => { - return <${singularPascalName}Cell ${idName}={${idName}} /> -} - -export default ${singularPascalName}Page diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.tsx copy.template deleted file mode 100644 index f4c5a5e541b2..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/pages/NamesPage.tsx copy.template +++ /dev/null @@ -1,7 +0,0 @@ -import ${pluralPascalName}Cell from '${importComponentNamesCell}' - -const ${pluralPascalName}Page = () => { - return <${pluralPascalName}Cell /> -} - -export default ${pluralPascalName}Page diff --git a/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.tsx copy.template b/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.tsx copy.template deleted file mode 100644 index afe1c6d178bb..000000000000 --- a/packages/cli/src/commands/generate/scaffold/templates/pages/NewNamePage.tsx copy.template +++ /dev/null @@ -1,7 +0,0 @@ -import New${singularPascalName} from '${importComponentNewName}' - -const New${singularPascalName}Page = () => { - return -} - -export default New${singularPascalName}Page From 0fc3c9b2a46b518ca60af628003f3fa6e67fbc28 Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Mon, 30 Dec 2024 09:41:06 -0600 Subject: [PATCH 08/18] fix(scaffold): correct typo in command name from 'destory' to 'destroy' --- packages/cli/src/commands/destroy/scaffold/scaffold.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/destroy/scaffold/scaffold.js b/packages/cli/src/commands/destroy/scaffold/scaffold.js index 62703aadf282..949a7b07d59d 100644 --- a/packages/cli/src/commands/destroy/scaffold/scaffold.js +++ b/packages/cli/src/commands/destroy/scaffold/scaffold.js @@ -114,7 +114,7 @@ export const tasks = ({ model, path, tests, nestScaffoldByModel }) => export const handler = async ({ model: modelArg }) => { recordTelemetryAttributes({ - command: 'destory scaffold', + command: 'destroy scaffold', }) const { model, path } = splitPathAndModel(modelArg) try { From a853a9f78e6c22f04e7c2346a17bb4e1aa33144e Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Mon, 30 Dec 2024 09:41:31 -0600 Subject: [PATCH 09/18] test(scaffold): update tests to expect 48 files instead of 19 --- .../generate/scaffold/__tests__/scaffold.test.js | 8 ++++---- .../scaffold/__tests__/scaffoldNoNest.test.js | 8 ++++---- .../generate/scaffold/__tests__/scaffoldPath.test.js | 8 ++++---- .../scaffold/__tests__/scaffoldPathMulti.test.js | 8 ++++---- .../__tests__/scaffoldPathMultiNoNest.test.js | 8 ++++---- .../scaffold/__tests__/scaffoldPathMultiword.test.js | 12 ++++++------ .../__tests__/scaffoldPathMultiwordNoNest.test.js | 12 ++++++------ .../scaffold/__tests__/scaffoldPathNoNest.test.js | 8 ++++---- .../cli/src/commands/generate/scaffold/scaffold.js | 4 ++-- 9 files changed, 38 insertions(+), 38 deletions(-) diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js index 233ed5beb4fe..40b081d51305 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js @@ -45,8 +45,8 @@ describe('in javascript (default) mode', () => { }) }) - test('returns exactly 19 files', async () => { - expect(Object.keys(files).length).toEqual(19) + test('returns exactly 48 files', async () => { + expect(Object.keys(files).length).toEqual(48) }) // SDL @@ -466,8 +466,8 @@ describe('in typescript mode', () => { }) }) - test('returns exactly 19 files', () => { - expect(Object.keys(tsFiles).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(tsFiles).length).toEqual(48) }) // SDL diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldNoNest.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldNoNest.test.js index abbfb05f6fba..26ee08d92431 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldNoNest.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldNoNest.test.js @@ -27,8 +27,8 @@ describe('in javascript (default) mode', () => { }) }) - test('returns exactly 19 files', () => { - expect(Object.keys(files).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(files).length).toEqual(48) }) // SDL @@ -308,8 +308,8 @@ describe('in typescript mode', () => { }) }) - test('returns exactly 19 files', () => { - expect(Object.keys(tsFiles).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(tsFiles).length).toEqual(48) }) // SDL diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPath.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPath.test.js index be52063bcaaf..f0630ceda792 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPath.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPath.test.js @@ -28,8 +28,8 @@ describe('admin/post', () => { }) describe('creates the correct files with the correct imports', () => { - it('returns exactly 19 files', () => { - expect(Object.keys(filesLower).length).toEqual(19) + it('returns exactly 48 files', () => { + expect(Object.keys(filesLower).length).toEqual(48) }) // Layout @@ -359,8 +359,8 @@ describe('Admin/Post', () => { }) describe('creates the correct files with the correct imports', () => { - it('returns exactly 19 files', () => { - expect(Object.keys(filesUpper).length).toEqual(19) + it('returns exactly 48 files', () => { + expect(Object.keys(filesUpper).length).toEqual(48) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMulti.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMulti.test.js index 2f65d0a0a645..07d1aa7aaae9 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMulti.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMulti.test.js @@ -28,8 +28,8 @@ describe('admin/pages/post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesNestedLower).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesNestedLower).length).toEqual(48) }) // Layout @@ -369,8 +369,8 @@ describe('Admin/Pages/Post/Post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesNestedUpper).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesNestedUpper).length).toEqual(48) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiNoNest.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiNoNest.test.js index 538995b4aaa2..a3656d143fa4 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiNoNest.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiNoNest.test.js @@ -28,8 +28,8 @@ describe('admin/pages/post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesNestedLower).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesNestedLower).length).toEqual(48) }) // Layout @@ -361,8 +361,8 @@ describe('Admin/Pages/Post/Post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesNestedUpper).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesNestedUpper).length).toEqual(48) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiword.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiword.test.js index 0d79faa24e19..ce0e9d03e179 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiword.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiword.test.js @@ -28,8 +28,8 @@ describe('AdminPages/Post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesMultiwordUpper).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesMultiwordUpper).length).toEqual(48) }) // Layout @@ -369,8 +369,8 @@ describe('admin-pages/Post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesMultiwordDash).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesMultiwordDash).length).toEqual(48) }) // Layout @@ -710,8 +710,8 @@ describe('admin_pages/Post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesMultiwordUnderscore).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesMultiwordUnderscore).length).toEqual(48) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiwordNoNest.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiwordNoNest.test.js index fe0d4c7b7c82..bef5c9031889 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiwordNoNest.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiwordNoNest.test.js @@ -28,8 +28,8 @@ describe('AdminPages/Post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesMultiwordUpper).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesMultiwordUpper).length).toEqual(48) }) // Layout @@ -361,8 +361,8 @@ describe('admin-pages/Post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesMultiwordDash).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesMultiwordDash).length).toEqual(48) }) // Layout @@ -694,8 +694,8 @@ describe('admin_pages/Post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesMultiwordUnderscore).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesMultiwordUnderscore).length).toEqual(48) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathNoNest.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathNoNest.test.js index c246c191b291..9267a37978d8 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathNoNest.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathNoNest.test.js @@ -28,8 +28,8 @@ describe('admin/Post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesLower).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesLower).length).toEqual(48) }) // Layout @@ -357,8 +357,8 @@ describe('Admin/Post', () => { }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 19 files', () => { - expect(Object.keys(filesUpper).length).toEqual(19) + test('returns exactly 48 files', () => { + expect(Object.keys(filesUpper).length).toEqual(48) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/scaffold.js b/packages/cli/src/commands/generate/scaffold/scaffold.js index a2d631480e06..64a448ab9d9b 100644 --- a/packages/cli/src/commands/generate/scaffold/scaffold.js +++ b/packages/cli/src/commands/generate/scaffold/scaffold.js @@ -528,7 +528,7 @@ const pageFiles = async ( const finalFolder = (nestScaffoldByModel ? singularName + '/' : '') + outputPageName - .replace(/(?:\.test|\.mock|\.stories)(?=\.ts)/, '') + .replace(/(?:\.test|\.mock|\.stories)(?=\.ts|\.js)/, '') .replace(/\.[jt]sx?/, '') const outputPath = path.join( @@ -625,7 +625,7 @@ const componentFiles = async ( const finalFolder = (nestScaffoldByModel ? singularName + '/' : '') + outputComponentName - .replace(/(?:\.test|\.mock|\.stories)(?=\.ts)/, '') + .replace(/(?:\.test|\.mock|\.stories)(?=\.ts|\.js)/, '') .replace(/\.[jt]sx?/, '') const outputPath = path.join( From 4263d32ca88abd55fdbfab19e59774bb7565a5ae Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Mon, 30 Dec 2024 09:58:50 -0600 Subject: [PATCH 10/18] feat(scaffold): add mock & test templates for all pages & components and update file count in tests --- .../scaffold/__tests__/scaffold.test.js | 62 +++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js index 40b081d51305..74bfba4a4423 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js @@ -876,34 +876,84 @@ describe('custom templates', () => { 'redwood.toml': '', 'web/generators/scaffold/pages/EditNamePage.tsx.template': 'export default function CustomEditPage() { return null }', + 'web/generators/scaffold/pages/EditNamePage.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', + 'web/generators/scaffold/pages/EditNamePage.test.tsx.template': + "it('renders page successfully', () => {})", 'web/generators/scaffold/pages/NewNamePage.tsx.template': 'export default function CustomNewPage() { return null }', + 'web/generators/scaffold/pages/NewNamePage.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', + 'web/generators/scaffold/pages/NewNamePage.test.tsx.template': + "it('renders page successfully', () => {})", 'web/generators/scaffold/pages/NamePage.tsx.template': 'export default function CustomPage() { return null }', - 'web/generators/scaffold/pages/NamesPage.tsx.template': - 'export default function CustomPluralPage() { return null }', 'web/generators/scaffold/pages/NamePage.stories.tsx.template': 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', 'web/generators/scaffold/pages/NamePage.test.tsx.template': "it('renders page successfully', () => {})", + 'web/generators/scaffold/pages/NamesPage.tsx.template': + 'export default function CustomPluralPage() { return null }', + 'web/generators/scaffold/pages/NamesPage.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', + 'web/generators/scaffold/pages/NamesPage.test.tsx.template': + "it('renders page successfully', () => {})", 'web/generators/scaffold/components/EditNameCell.tsx.template': 'export const Success = () => null', - 'web/generators/scaffold/components/Name.tsx.template': - 'export default function ${singularPascalName}() { return null }', + 'web/generators/scaffold/components/EditNameCell.mock.tsx.template': + 'export const standard = () => ({})', + 'web/generators/scaffold/components/EditNameCell.test.tsx.template': + "it('renders component successfully', () => {})", + 'web/generators/scaffold/components/EditNameCell.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', + 'web/generators/scaffold/components/NameCell.mock.tsx.template': + 'export const standard = () => ({})', + 'web/generators/scaffold/components/NameCell.test.tsx.template': + "it('renders component successfully', () => {})", + 'web/generators/scaffold/components/NameCell.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', 'web/generators/scaffold/components/NameCell.tsx.template': 'export const Success = () => null', 'web/generators/scaffold/components/NameForm.tsx.template': 'export default function ${singularPascalName}Form() { return null }', + 'web/generators/scaffold/components/NameForm.mock.tsx.template': + 'export const standard = () => ({})', + 'web/generators/scaffold/components/NameForm.test.tsx.template': + "it('renders component successfully', () => {})", + 'web/generators/scaffold/components/NameForm.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', 'web/generators/scaffold/components/Names.tsx.template': 'export default function ${singularPascalName}List() { return null }', + 'web/generators/scaffold/components/Names.mock.tsx.template': + 'export const standard = () => ({})', + 'web/generators/scaffold/components/Names.test.tsx.template': + "it('renders component successfully', () => {})", + 'web/generators/scaffold/components/Names.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', 'web/generators/scaffold/components/NamesCell.tsx.template': 'export const Success = () => null', + 'web/generators/scaffold/components/NamesCell.mock.tsx.template': + 'export const standard = () => ({})', + 'web/generators/scaffold/components/NamesCell.test.tsx.template': + "it('renders component successfully', () => {})", + 'web/generators/scaffold/components/NamesCell.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', 'web/generators/scaffold/components/NewName.tsx.template': 'export default function New${singularPascalName}() { return null }', + 'web/generators/scaffold/components/NewName.mock.tsx.template': + 'export const standard = () => ({})', + 'web/generators/scaffold/components/NewName.test.tsx.template': + "it('renders component successfully', () => {})", + 'web/generators/scaffold/components/NewName.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', + 'web/generators/scaffold/components/Name.tsx.template': + 'export default function ${singularPascalName}() { return null }', 'web/generators/scaffold/components/Name.mock.ts.template': 'export const standard = () => ({ custom: "" })', 'web/generators/scaffold/components/Name.test.tsx.template': "it('renders component successfully', () => {})", + 'web/generators/scaffold/components/Name.stories.tsx.template': + 'const customMeta = {}\nexport default customMeta\nexport const Primary = {}', }, process.env.RWJS_CWD, ) @@ -922,8 +972,8 @@ describe('custom templates', () => { process.env.RWJS_CWD = originalRwjsCwd }) - test('returns exactly 23 files', () => { - expect(Object.keys(tsFiles).length).toEqual(23) + test('returns exactly 48 files', () => { + expect(Object.keys(tsFiles).length).toEqual(48) }) test('creates an Edit page', async () => { From ce10dcfcc288070e4cde0a5101563413297f68d0 Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Mon, 30 Dec 2024 16:02:39 -0600 Subject: [PATCH 11/18] refactor(scaffold): restore default functionality and update tests --- .../__snapshots__/scaffold.test.js.snap | 112 ++++++++++++++++++ .../scaffold/__tests__/scaffold.test.js | 33 ++++-- .../scaffold/__tests__/scaffoldNoNest.test.js | 10 +- .../scaffold/__tests__/scaffoldPath.test.js | 10 +- .../__tests__/scaffoldPathMulti.test.js | 10 +- .../__tests__/scaffoldPathMultiNoNest.test.js | 10 +- .../__tests__/scaffoldPathMultiword.test.js | 15 +-- .../scaffoldPathMultiwordNoNest.test.js | 15 +-- .../__tests__/scaffoldPathNoNest.test.js | 10 +- .../commands/generate/scaffold/scaffold.js | 93 ++++++++++++--- 10 files changed, 246 insertions(+), 72 deletions(-) diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffold.test.js.snap b/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffold.test.js.snap index 90187e50c576..bd869d2346e0 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffold.test.js.snap +++ b/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffold.test.js.snap @@ -266,6 +266,118 @@ export default ScaffoldLayout " `; +exports[`custom templates > creates a service 1`] = ` +"import type { + QueryResolvers, + MutationResolvers, + PostRelationResolvers, +} from 'types/graphql' + +import { db } from 'src/lib/db' + +export const posts: QueryResolvers['posts'] = () => { + return db.post.findMany() +} + +export const post: QueryResolvers['post'] = ({ id }) => { + return db.post.findUnique({ + where: { id }, + }) +} + +export const createPost: MutationResolvers['createPost'] = ({ input }) => { + return db.post.create({ + data: input, + }) +} + +export const updatePost: MutationResolvers['updatePost'] = ({ id, input }) => { + return db.post.update({ + data: input, + where: { id }, + }) +} + +export const deletePost: MutationResolvers['deletePost'] = ({ id }) => { + return db.post.delete({ + where: { id }, + }) +} + +export const Post: PostRelationResolvers = { + favorites: (_obj, { root }) => { + return db.post.findUnique({ where: { id: root?.id } }).favorites() + }, + tag: (_obj, { root }) => { + return db.post.findUnique({ where: { id: root?.id } }).tag() + }, +} +" +`; + +exports[`custom templates > creates a service test 1`] = ` +"import type { Post } from '@prisma/client' + +import { posts, post, createPost, updatePost, deletePost } from './posts' +import type { StandardScenario } from './posts.scenarios' + +// Generated boilerplate tests do not account for all circumstances +// and can fail without adjustments, e.g. Float. +// Please refer to the RedwoodJS Testing Docs: +// https://redwoodjs.com/docs/testing#testing-services +// https://redwoodjs.com/docs/testing#jest-expect-type-considerations + +describe('posts', () => { + scenario('returns all posts', async (scenario: StandardScenario) => { + const result = await posts() + + expect(result.length).toEqual(Object.keys(scenario.post).length) + }) + + scenario('returns a single post', async (scenario: StandardScenario) => { + const result = await post({ id: scenario.post.one.id }) + + expect(result).toEqual(scenario.post.one) + }) + + scenario('creates a post', async () => { + const result = await createPost({ + input: { + title: 'String', + slug: 'String1234567', + author: 'String', + body: 'String', + metadata: { foo: 'bar' }, + }, + }) + + expect(result.title).toEqual('String') + expect(result.slug).toEqual('String1234567') + expect(result.author).toEqual('String') + expect(result.body).toEqual('String') + expect(result.metadata).toEqual({ foo: 'bar' }) + }) + + scenario('updates a post', async (scenario: StandardScenario) => { + const original = (await post({ id: scenario.post.one.id })) as Post + const result = await updatePost({ + id: original.id, + input: { title: 'String2' }, + }) + + expect(result.title).toEqual('String2') + }) + + scenario('deletes a post', async (scenario: StandardScenario) => { + const original = (await deletePost({ id: scenario.post.one.id })) as Post + const result = await post({ id: original.id }) + + expect(result).toEqual(null) + }) +}) +" +`; + exports[`custom templates > creates an sdl 1`] = ` "export const schema = gql\` type Post { diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js index 74bfba4a4423..6e70d41bb96b 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffold.test.js @@ -40,13 +40,12 @@ describe('in javascript (default) mode', () => { files = await scaffold.files({ ...getDefaultArgs(defaults), model: 'Post', - tests: true, nestScaffoldByModel: true, }) }) - test('returns exactly 48 files', async () => { - expect(Object.keys(files).length).toEqual(48) + test('returns exactly 19 files', async () => { + expect(Object.keys(files).length).toEqual(19) }) // SDL @@ -299,7 +298,6 @@ describe('in javascript (default) mode', () => { scaffold.files({ ...getDefaultArgs(defaults), model: 'NoEditableField', - tests: true, nestScaffoldByModel: true, }), ).rejects.toThrow( @@ -461,13 +459,12 @@ describe('in typescript mode', () => { ...getDefaultArgs(defaults), model: 'Post', typescript: true, - tests: true, nestScaffoldByModel: true, }) }) - test('returns exactly 48 files', () => { - expect(Object.keys(tsFiles).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(tsFiles).length).toEqual(19) }) // SDL @@ -962,8 +959,10 @@ describe('custom templates', () => { force: false, model: 'Post', typescript: true, - tests: true, nestScaffoldByModel: true, + tests: true, + stories: true, + serviceTests: true, }) }) @@ -1100,6 +1099,24 @@ describe('custom templates', () => { ).toMatchSnapshot() }) + // Service + + test('creates a service', () => { + expect( + tsFiles[ + path.normalize('/path/to/project/api/src/services/posts/posts.ts') + ], + ).toMatchSnapshot() + }) + + test('creates a service test', () => { + expect( + tsFiles[ + path.normalize('/path/to/project/api/src/services/posts/posts.test.ts') + ], + ).toMatchSnapshot() + }) + // Layout // (Including this in the test just to make sure we're testing at least one // web-side file that we don't have a custom template for) diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldNoNest.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldNoNest.test.js index 26ee08d92431..d3060e6a92a4 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldNoNest.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldNoNest.test.js @@ -22,13 +22,12 @@ describe('in javascript (default) mode', () => { files = await scaffold.files({ ...getDefaultArgs(defaults), model: 'Post', - tests: true, nestScaffoldByModel: false, }) }) - test('returns exactly 48 files', () => { - expect(Object.keys(files).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(files).length).toEqual(19) }) // SDL @@ -303,13 +302,12 @@ describe('in typescript mode', () => { ...getDefaultArgs(defaults), model: 'Post', typescript: true, - tests: true, nestScaffoldByModel: false, }) }) - test('returns exactly 48 files', () => { - expect(Object.keys(tsFiles).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(tsFiles).length).toEqual(19) }) // SDL diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPath.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPath.test.js index f0630ceda792..4457e4bbbb0a 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPath.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPath.test.js @@ -22,14 +22,13 @@ describe('admin/post', () => { filesLower = await scaffold.files({ model: 'Post', path: 'admin', - tests: true, nestScaffoldByModel: true, }) }) describe('creates the correct files with the correct imports', () => { - it('returns exactly 48 files', () => { - expect(Object.keys(filesLower).length).toEqual(48) + it('returns exactly 19 files', () => { + expect(Object.keys(filesLower).length).toEqual(19) }) // Layout @@ -353,14 +352,13 @@ describe('Admin/Post', () => { filesUpper = await scaffold.files({ model: 'Post', path: 'Admin', - tests: true, nestScaffoldByModel: true, }) }) describe('creates the correct files with the correct imports', () => { - it('returns exactly 48 files', () => { - expect(Object.keys(filesUpper).length).toEqual(48) + it('returns exactly 19 files', () => { + expect(Object.keys(filesUpper).length).toEqual(19) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMulti.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMulti.test.js index 07d1aa7aaae9..60a3eaf3d221 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMulti.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMulti.test.js @@ -22,14 +22,13 @@ describe('admin/pages/post', () => { filesNestedLower = await scaffold.files({ model: 'Post', path: 'admin/pages', - tests: true, nestScaffoldByModel: true, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesNestedLower).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesNestedLower).length).toEqual(19) }) // Layout @@ -363,14 +362,13 @@ describe('Admin/Pages/Post/Post', () => { filesNestedUpper = await scaffold.files({ model: 'Post', path: 'Admin/Pages', - tests: true, nestScaffoldByModel: true, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesNestedUpper).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesNestedUpper).length).toEqual(19) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiNoNest.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiNoNest.test.js index a3656d143fa4..86e45613461b 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiNoNest.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiNoNest.test.js @@ -22,14 +22,13 @@ describe('admin/pages/post', () => { filesNestedLower = await scaffold.files({ model: 'Post', path: 'admin/pages', - tests: true, nestScaffoldByModel: false, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesNestedLower).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesNestedLower).length).toEqual(19) }) // Layout @@ -355,14 +354,13 @@ describe('Admin/Pages/Post/Post', () => { filesNestedUpper = await scaffold.files({ model: 'Post', path: 'Admin/Pages', - tests: true, nestScaffoldByModel: false, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesNestedUpper).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesNestedUpper).length).toEqual(19) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiword.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiword.test.js index ce0e9d03e179..8e3da6ca4858 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiword.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiword.test.js @@ -22,14 +22,13 @@ describe('AdminPages/Post', () => { filesMultiwordUpper = await scaffold.files({ model: 'Post', path: 'AdminPages', - tests: true, nestScaffoldByModel: true, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesMultiwordUpper).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesMultiwordUpper).length).toEqual(19) }) // Layout @@ -363,14 +362,13 @@ describe('admin-pages/Post', () => { filesMultiwordDash = await scaffold.files({ model: 'Post', path: 'admin-pages', - tests: true, nestScaffoldByModel: true, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesMultiwordDash).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesMultiwordDash).length).toEqual(19) }) // Layout @@ -704,14 +702,13 @@ describe('admin_pages/Post', () => { filesMultiwordUnderscore = await scaffold.files({ model: 'Post', path: 'admin_pages', - tests: true, nestScaffoldByModel: true, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesMultiwordUnderscore).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesMultiwordUnderscore).length).toEqual(19) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiwordNoNest.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiwordNoNest.test.js index bef5c9031889..5c51cecfe048 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiwordNoNest.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathMultiwordNoNest.test.js @@ -22,14 +22,13 @@ describe('AdminPages/Post', () => { filesMultiwordUpper = await scaffold.files({ model: 'Post', path: 'AdminPages', - tests: true, nestScaffoldByModel: false, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesMultiwordUpper).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesMultiwordUpper).length).toEqual(19) }) // Layout @@ -355,14 +354,13 @@ describe('admin-pages/Post', () => { filesMultiwordDash = await scaffold.files({ model: 'Post', path: 'admin-pages', - tests: true, nestScaffoldByModel: false, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesMultiwordDash).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesMultiwordDash).length).toEqual(19) }) // Layout @@ -688,14 +686,13 @@ describe('admin_pages/Post', () => { filesMultiwordUnderscore = await scaffold.files({ model: 'Post', path: 'admin_pages', - tests: true, nestScaffoldByModel: false, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesMultiwordUnderscore).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesMultiwordUnderscore).length).toEqual(19) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathNoNest.test.js b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathNoNest.test.js index 9267a37978d8..afd37fb75a25 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathNoNest.test.js +++ b/packages/cli/src/commands/generate/scaffold/__tests__/scaffoldPathNoNest.test.js @@ -22,14 +22,13 @@ describe('admin/Post', () => { filesLower = await scaffold.files({ model: 'Post', path: 'admin', - tests: true, nestScaffoldByModel: false, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesLower).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesLower).length).toEqual(19) }) // Layout @@ -351,14 +350,13 @@ describe('Admin/Post', () => { filesUpper = await scaffold.files({ model: 'Post', path: 'Admin', - tests: true, nestScaffoldByModel: false, }) }) describe('creates the correct files with the correct imports', () => { - test('returns exactly 48 files', () => { - expect(Object.keys(filesUpper).length).toEqual(48) + test('returns exactly 19 files', () => { + expect(Object.keys(filesUpper).length).toEqual(19) }) // Layout diff --git a/packages/cli/src/commands/generate/scaffold/scaffold.js b/packages/cli/src/commands/generate/scaffold/scaffold.js index 64a448ab9d9b..a7e5a1000020 100644 --- a/packages/cli/src/commands/generate/scaffold/scaffold.js +++ b/packages/cli/src/commands/generate/scaffold/scaffold.js @@ -143,11 +143,13 @@ export const files = async ({ docs, model: name, path: scaffoldPath = '', - tests = true, + tests, typescript = false, tailwind = false, force = false, nestScaffoldByModel, + stories, + serviceTests = true, }) => { const model = await getSchema(name) if (typeof nestScaffoldByModel === 'undefined') { @@ -168,8 +170,10 @@ export const files = async ({ name, pascalScaffoldPath, typescript, + tests, nestScaffoldByModel, templateStrings, + stories, )), ...(await sdlFiles({ ...getDefaultArgs(sdlBuilder), @@ -182,7 +186,7 @@ export const files = async ({ name, crud: true, relations: relationsForModel(model), - tests, + tests: serviceTests || tests, typescript, })), ...(await assetFiles(name, tailwind)), @@ -193,7 +197,9 @@ export const files = async ({ pascalScaffoldPath, typescript, nestScaffoldByModel, + tests, templateStrings, + stories, )), } } @@ -498,7 +504,9 @@ const pageFiles = async ( pascalScaffoldPath = '', generateTypescript, nestScaffoldByModel = true, + tests, templateStrings, + stories, ) => { const pluralName = pascalcase(pluralize(name)) const singularName = pascalcase(singularize(name)) @@ -509,13 +517,24 @@ const pageFiles = async ( let fileList = {} - const pages = fs.readdirSync( - customOrDefaultTemplatePath({ - side: 'web', - generator: 'scaffold', - templatePath: 'pages', - }), - ) + const pages = fs + .readdirSync( + customOrDefaultTemplatePath({ + side: 'web', + generator: 'scaffold', + templatePath: 'pages', + }), + ) + .filter((c) => { + if (!tests && c.match(/\.test\./)) { + return false + } + + if (!stories && c.match(/\.stories\./)) { + return false + } + return true + }) for (const page of pages) { // Sanitize page names @@ -595,8 +614,10 @@ const componentFiles = async ( name, pascalScaffoldPath = '', generateTypescript, + tests, nestScaffoldByModel = true, templateStrings, + stories, ) => { const pluralName = pascalcase(pluralize(name)) const singularName = pascalcase(singularize(name)) @@ -607,13 +628,28 @@ const componentFiles = async ( const intForeignKeys = intForeignKeysForModel(model) let fileList = {} - const components = fs.readdirSync( - customOrDefaultTemplatePath({ - side: 'web', - generator: 'scaffold', - templatePath: 'components', - }), - ) + const components = fs + .readdirSync( + customOrDefaultTemplatePath({ + side: 'web', + generator: 'scaffold', + templatePath: 'components', + }), + ) + .filter((c) => { + if (!tests && c.match(/\.test\./)) { + return false + } + + if (!stories && c.match(/\.stories\./)) { + return false + } + + if (!stories && !tests && c.match(/\.mock\./)) { + return false + } + return true + }) for (const component of components) { const outputComponentName = component @@ -809,6 +845,15 @@ export const builder = (yargs) => { description: 'Generate test files', type: 'boolean', }) + .option('serviceTests', { + description: 'Generate test files for the service', + type: 'boolean', + default: true, + }) + .option('stories', { + description: 'Generate storybook files', + type: 'boolean', + }) .option('tailwind', { description: 'Generate TailwindCSS version of scaffold.css (automatically set to `true` if TailwindCSS config exists)', @@ -841,6 +886,8 @@ export const tasks = ({ typescript, javascript, tailwind, + stories, + serviceTests, }) => { return new Listr( [ @@ -856,6 +903,8 @@ export const tasks = ({ javascript, tailwind, force, + stories, + serviceTests, }) return writeFilesTask(f, { overwriteExisting: force }) }, @@ -908,10 +957,18 @@ export const handler = async ({ tailwind, docs = false, rollback, + stories, + serviceTests = true, }) => { if (tests === undefined) { tests = getConfig().generate.tests } + if (stories === undefined) { + stories = getConfig().generate.stories + } + if (serviceTests === undefined) { + serviceTests = getConfig().generate.serviceTests + } recordTelemetryAttributes({ command: 'generate scaffold', force, @@ -920,6 +977,8 @@ export const handler = async ({ tailwind, docs, rollback, + stories, + serviceTests, }) const { model, path } = splitPathAndModel(modelArg) @@ -936,6 +995,8 @@ export const handler = async ({ tests, typescript, tailwind, + stories, + serviceTests, }) if (rollback && !force) { prepareForRollback(t) From be06b9c3c011dbe5f1e3c0f4f31094ddac0b89bc Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Mon, 30 Dec 2024 16:12:06 -0600 Subject: [PATCH 12/18] chore(changelog): update changelog description --- .changesets/11755.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.changesets/11755.md b/.changesets/11755.md index f6c96a06f798..c0802c308dfb 100644 --- a/.changesets/11755.md +++ b/.changesets/11755.md @@ -1,3 +1,5 @@ - fix(cli): Allow common custom scaffold template files (#11755) by @esteban-url Adds the ability to generate test, stories and mock files when custom scaffold templates are in use. + +Adds initial tests, stories and mocks to the generator they can generated by using the flags `--tests` and `--stories` From d11aa8f49ffb180ff77a928c72c6aab71b62c6da Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Wed, 1 Jan 2025 18:38:52 +0700 Subject: [PATCH 13/18] test() instead of match() --- .../cli/src/commands/generate/scaffold/scaffold.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/commands/generate/scaffold/scaffold.js b/packages/cli/src/commands/generate/scaffold/scaffold.js index a7e5a1000020..092770e827ac 100644 --- a/packages/cli/src/commands/generate/scaffold/scaffold.js +++ b/packages/cli/src/commands/generate/scaffold/scaffold.js @@ -526,13 +526,14 @@ const pageFiles = async ( }), ) .filter((c) => { - if (!tests && c.match(/\.test\./)) { + if (!tests && /\.test\./.test(c)) { return false } - if (!stories && c.match(/\.stories\./)) { + if (!stories && /\.stories\./.test(c)) { return false } + return true }) @@ -637,17 +638,18 @@ const componentFiles = async ( }), ) .filter((c) => { - if (!tests && c.match(/\.test\./)) { + if (!tests && /\.test\./.test(c)) { return false } - if (!stories && c.match(/\.stories\./)) { + if (!stories && /\.stories\./.test(c)) { return false } - if (!stories && !tests && c.match(/\.mock\./)) { + if (!stories && !tests && /\.mock\./.test(c)) { return false } + return true }) From cf9d91a272bcc308b19d788cd77dfa56b3a432ff Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Wed, 1 Jan 2025 18:39:22 +0700 Subject: [PATCH 14/18] test-project update --- .../Contact/Contact/Contact.mock.ts | 10 ++++++ .../Contact/Contact/Contact.stories.tsx | 26 ++++++++++++++ .../Contact/Contact/Contact.test.tsx | 15 ++++++++ .../Contact/ContactCell/ContactCell.mock.ts | 10 ++++++ .../ContactCell/ContactCell.stories.tsx | 29 +++++++++++++++ .../Contact/ContactCell/ContactCell.test.tsx | 25 +++++++++++++ .../Contact/ContactForm/ContactForm.mock.ts | 10 ++++++ .../ContactForm/ContactForm.stories.tsx | 26 ++++++++++++++ .../Contact/ContactForm/ContactForm.test.tsx | 14 ++++++++ .../Contact/Contacts/Contacts.mock.ts | 19 ++++++++++ .../Contact/Contacts/Contacts.stories.tsx | 26 ++++++++++++++ .../Contact/Contacts/Contacts.test.tsx | 15 ++++++++ .../Contact/ContactsCell/ContactsCell.mock.ts | 19 ++++++++++ .../ContactsCell/ContactsCell.stories.tsx | 35 +++++++++++++++++++ .../ContactsCell/ContactsCell.test.tsx | 30 ++++++++++++++++ .../EditContactCell/EditContactCell.mock.ts | 10 ++++++ .../EditContactCell.stories.tsx | 29 +++++++++++++++ .../EditContactCell/EditContactCell.test.tsx | 25 +++++++++++++ .../Contact/NewContact/NewContact.mock.ts | 10 ++++++ .../Contact/NewContact/NewContact.stories.tsx | 26 ++++++++++++++ .../Contact/NewContact/NewContact.test.tsx | 14 ++++++++ .../Post/EditPostCell/EditPostCell.mock.ts | 17 +++++++++ .../EditPostCell/EditPostCell.stories.tsx | 29 +++++++++++++++ .../Post/EditPostCell/EditPostCell.test.tsx | 25 +++++++++++++ .../components/Post/NewPost/NewPost.mock.ts | 17 +++++++++ .../Post/NewPost/NewPost.stories.tsx | 26 ++++++++++++++ .../components/Post/NewPost/NewPost.test.tsx | 14 ++++++++ .../web/src/components/Post/Post/Post.mock.ts | 17 +++++++++ .../src/components/Post/Post/Post.stories.tsx | 26 ++++++++++++++ .../src/components/Post/Post/Post.test.tsx | 15 ++++++++ .../components/Post/PostCell/PostCell.mock.ts | 17 +++++++++ .../Post/PostCell/PostCell.stories.tsx | 29 +++++++++++++++ .../Post/PostCell/PostCell.test.tsx | 25 +++++++++++++ .../components/Post/PostForm/PostForm.mock.ts | 17 +++++++++ .../Post/PostForm/PostForm.stories.tsx | 26 ++++++++++++++ .../Post/PostForm/PostForm.test.tsx | 14 ++++++++ .../src/components/Post/Posts/Posts.mock.ts | 33 +++++++++++++++++ .../components/Post/Posts/Posts.stories.tsx | 26 ++++++++++++++ .../src/components/Post/Posts/Posts.test.tsx | 15 ++++++++ .../Post/PostsCell/PostsCell.mock.ts | 33 +++++++++++++++++ .../Post/PostsCell/PostsCell.stories.tsx | 35 +++++++++++++++++++ .../Post/PostsCell/PostsCell.test.tsx | 30 ++++++++++++++++ .../ContactPage/ContactPage.stories.tsx | 13 +++++++ .../Contact/ContactPage/ContactPage.test.tsx | 14 ++++++++ .../ContactsPage/ContactsPage.stories.tsx | 13 +++++++ .../ContactsPage/ContactsPage.test.tsx | 14 ++++++++ .../EditContactPage.stories.tsx | 13 +++++++ .../EditContactPage/EditContactPage.test.tsx | 14 ++++++++ .../NewContactPage/NewContactPage.stories.tsx | 13 +++++++ .../NewContactPage/NewContactPage.test.tsx | 14 ++++++++ .../EditPostPage/EditPostPage.stories.tsx | 13 +++++++ .../Post/EditPostPage/EditPostPage.test.tsx | 14 ++++++++ .../Post/NewPostPage/NewPostPage.stories.tsx | 13 +++++++ .../Post/NewPostPage/NewPostPage.test.tsx | 14 ++++++++ .../pages/Post/PostPage/PostPage.stories.tsx | 13 +++++++ .../src/pages/Post/PostPage/PostPage.test.tsx | 14 ++++++++ .../Post/PostsPage/PostsPage.stories.tsx | 13 +++++++ .../pages/Post/PostsPage/PostsPage.test.tsx | 14 ++++++++ 58 files changed, 1125 insertions(+) create mode 100644 __fixtures__/test-project/web/src/components/Contact/Contact/Contact.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Contact/Contact/Contact.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/Contact/Contact.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/NewPost/NewPost.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Post/NewPost/NewPost.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/NewPost/NewPost.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/Post/Post.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Post/Post/Post.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/Post/Post.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/PostCell/PostCell.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Post/PostCell/PostCell.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/PostCell/PostCell.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/PostForm/PostForm.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Post/PostForm/PostForm.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/PostForm/PostForm.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/Posts/Posts.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Post/Posts/Posts.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/Posts/Posts.test.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.mock.ts create mode 100644 __fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.stories.tsx create mode 100644 __fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.test.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Contact/ContactPage/ContactPage.stories.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Contact/ContactPage/ContactPage.test.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Contact/ContactsPage/ContactsPage.stories.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Contact/ContactsPage/ContactsPage.test.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Contact/EditContactPage/EditContactPage.stories.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Contact/EditContactPage/EditContactPage.test.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Contact/NewContactPage/NewContactPage.stories.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Contact/NewContactPage/NewContactPage.test.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Post/EditPostPage/EditPostPage.stories.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Post/EditPostPage/EditPostPage.test.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Post/NewPostPage/NewPostPage.stories.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Post/NewPostPage/NewPostPage.test.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Post/PostPage/PostPage.stories.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Post/PostPage/PostPage.test.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Post/PostsPage/PostsPage.stories.tsx create mode 100644 __fixtures__/test-project/web/src/pages/Post/PostsPage/PostsPage.test.tsx diff --git a/__fixtures__/test-project/web/src/components/Contact/Contact/Contact.mock.ts b/__fixtures__/test-project/web/src/components/Contact/Contact/Contact.mock.ts new file mode 100644 index 000000000000..420e723ce7ac --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/Contact/Contact.mock.ts @@ -0,0 +1,10 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + contact: { + __typename: 'Contact', + id: 42, + name: 'String', + email: 'String', + message: 'String', + }, +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/Contact/Contact.stories.tsx b/__fixtures__/test-project/web/src/components/Contact/Contact/Contact.stories.tsx new file mode 100644 index 000000000000..93034e7224bd --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/Contact/Contact.stories.tsx @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import Contact from './Contact' + +const meta: Meta = { + component: Contact, + tags: ['autodocs'], +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/components/Contact/Contact/Contact.test.tsx b/__fixtures__/test-project/web/src/components/Contact/Contact/Contact.test.tsx new file mode 100644 index 000000000000..9ec1c38395c9 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/Contact/Contact.test.tsx @@ -0,0 +1,15 @@ +import { render } from '@redwoodjs/testing/web' + +import Contact from './Contact' +import { standard } from './Contact.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('Contact', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.mock.ts b/__fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.mock.ts new file mode 100644 index 000000000000..420e723ce7ac --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.mock.ts @@ -0,0 +1,10 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + contact: { + __typename: 'Contact', + id: 42, + name: 'String', + email: 'String', + message: 'String', + }, +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.stories.tsx b/__fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.stories.tsx new file mode 100644 index 000000000000..fc6c14684400 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.stories.tsx @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { Loading, Failure, Success } from './ContactCell' +import { standard } from './ContactCell.mock' + +const meta: Meta = { + title: 'Cells/ContactCell', + tags: ['autodocs'], +} + +export default meta + +export const loading: StoryObj = { + render: () => { + return Loading ? : <> + }, +} + +export const failure: StoryObj = { + render: (args) => { + return Failure ? : <> + }, +} + +export const success: StoryObj = { + render: (args) => { + return Success ? : <> + }, +} diff --git a/__fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.test.tsx b/__fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.test.tsx new file mode 100644 index 000000000000..6317dd1220cf --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/ContactCell/ContactCell.test.tsx @@ -0,0 +1,25 @@ +import { render } from '@redwoodjs/testing/web' + +import { Loading, Failure, Success } from './ContactCell' +import { standard } from './ContactCell.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('ContactCell', () => { + it('renders loading successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders failure successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.mock.ts b/__fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.mock.ts new file mode 100644 index 000000000000..420e723ce7ac --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.mock.ts @@ -0,0 +1,10 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + contact: { + __typename: 'Contact', + id: 42, + name: 'String', + email: 'String', + message: 'String', + }, +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.stories.tsx b/__fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.stories.tsx new file mode 100644 index 000000000000..0fc1a74b473e --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.stories.tsx @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import ContactForm from './ContactForm' + +const meta: Meta = { + component: ContactForm, + tags: ['autodocs'], +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.test.tsx b/__fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.test.tsx new file mode 100644 index 000000000000..52d42ded4975 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/ContactForm/ContactForm.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import ContactForm from './ContactForm' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('ContactForm', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.mock.ts b/__fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.mock.ts new file mode 100644 index 000000000000..c4e4f2b5cef5 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.mock.ts @@ -0,0 +1,19 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + contacts: [ + { + __typename: 'Contact', + id: 42, + name: 'String', + email: 'String', + message: 'String', + }, + { + __typename: 'Contact', + id: 43, + name: 'String', + email: 'String', + message: 'String', + }, + ], +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.stories.tsx b/__fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.stories.tsx new file mode 100644 index 000000000000..8f0f0911c0b3 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.stories.tsx @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import Contacts from './Contacts' + +const meta: Meta = { + component: Contacts, + tags: ['autodocs'], +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.test.tsx b/__fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.test.tsx new file mode 100644 index 000000000000..acb994246964 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/Contacts/Contacts.test.tsx @@ -0,0 +1,15 @@ +import { render } from '@redwoodjs/testing/web' + +import Contacts from './Contacts' +import { standard } from './Contacts.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('Contacts', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.mock.ts b/__fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.mock.ts new file mode 100644 index 000000000000..c4e4f2b5cef5 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.mock.ts @@ -0,0 +1,19 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + contacts: [ + { + __typename: 'Contact', + id: 42, + name: 'String', + email: 'String', + message: 'String', + }, + { + __typename: 'Contact', + id: 43, + name: 'String', + email: 'String', + message: 'String', + }, + ], +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.stories.tsx b/__fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.stories.tsx new file mode 100644 index 000000000000..1fa33a5488e5 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.stories.tsx @@ -0,0 +1,35 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { Loading, Empty, Failure, Success } from './ContactsCell' +import { standard } from './ContactsCell.mock' + +const meta: Meta = { + title: 'Cells/ContactsCell', + tags: ['autodocs'], +} + +export default meta + +export const loading: StoryObj = { + render: () => { + return Loading ? : <> + }, +} + +export const failure: StoryObj = { + render: (args) => { + return Failure ? : <> + }, +} + +export const empty: StoryObj = { + render: (args) => { + return Empty ? : <> + }, +} + +export const success: StoryObj = { + render: (args) => { + return Success ? : <> + }, +} diff --git a/__fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.test.tsx b/__fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.test.tsx new file mode 100644 index 000000000000..d151074d6147 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/ContactsCell/ContactsCell.test.tsx @@ -0,0 +1,30 @@ +import { render } from '@redwoodjs/testing/web' + +import { Loading, Failure, Empty, Success } from './ContactsCell' +import { standard } from './ContactsCell.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('ContactsCell', () => { + it('renders loading successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders failure successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders empty successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.mock.ts b/__fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.mock.ts new file mode 100644 index 000000000000..420e723ce7ac --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.mock.ts @@ -0,0 +1,10 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + contact: { + __typename: 'Contact', + id: 42, + name: 'String', + email: 'String', + message: 'String', + }, +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.stories.tsx b/__fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.stories.tsx new file mode 100644 index 000000000000..809bf4c5dd38 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.stories.tsx @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { Loading, Failure, Success } from './EditContactCell' +import { standard } from './EditContactCell.mock' + +const meta: Meta = { + title: 'Cells/EditContactCell', + tags: ['autodocs'], +} + +export default meta + +export const loading: StoryObj = { + render: () => { + return Loading ? : <> + }, +} + +export const failure: StoryObj = { + render: (args) => { + return Failure ? : <> + }, +} + +export const success: StoryObj = { + render: (args) => { + return Success ? : <> + }, +} diff --git a/__fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.test.tsx b/__fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.test.tsx new file mode 100644 index 000000000000..65c656db83d0 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/EditContactCell/EditContactCell.test.tsx @@ -0,0 +1,25 @@ +import { render } from '@redwoodjs/testing/web' + +import { Loading, Failure, Success } from './EditContactCell' +import { standard } from './EditContactCell.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('EditContactCell', () => { + it('renders loading successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders failure successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.mock.ts b/__fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.mock.ts new file mode 100644 index 000000000000..420e723ce7ac --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.mock.ts @@ -0,0 +1,10 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + contact: { + __typename: 'Contact', + id: 42, + name: 'String', + email: 'String', + message: 'String', + }, +}) diff --git a/__fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.stories.tsx b/__fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.stories.tsx new file mode 100644 index 000000000000..65ec426af8aa --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.stories.tsx @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import NewContact from './NewContact' + +const meta: Meta = { + component: NewContact, + tags: ['autodocs'], +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.test.tsx b/__fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.test.tsx new file mode 100644 index 000000000000..b6c8e4a656a5 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Contact/NewContact/NewContact.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import NewContact from './NewContact' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('NewContact', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.mock.ts b/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.mock.ts new file mode 100644 index 000000000000..2e72f708b4c0 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.mock.ts @@ -0,0 +1,17 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + post: { + __typename: 'Post', + id: 42, + title: 'String', + body: 'String', + author: { + create: { + email: 'String1253984', + hashedPassword: 'String', + fullName: 'String', + salt: 'String', + }, + }, + }, +}) diff --git a/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.stories.tsx b/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.stories.tsx new file mode 100644 index 000000000000..e93f1b911d69 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.stories.tsx @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { Loading, Failure, Success } from './EditPostCell' +import { standard } from './EditPostCell.mock' + +const meta: Meta = { + title: 'Cells/EditPostCell', + tags: ['autodocs'], +} + +export default meta + +export const loading: StoryObj = { + render: () => { + return Loading ? : <> + }, +} + +export const failure: StoryObj = { + render: (args) => { + return Failure ? : <> + }, +} + +export const success: StoryObj = { + render: (args) => { + return Success ? : <> + }, +} diff --git a/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.test.tsx b/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.test.tsx new file mode 100644 index 000000000000..b5527b040444 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.test.tsx @@ -0,0 +1,25 @@ +import { render } from '@redwoodjs/testing/web' + +import { Loading, Failure, Success } from './EditPostCell' +import { standard } from './EditPostCell.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('EditPostCell', () => { + it('renders loading successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders failure successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.mock.ts b/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.mock.ts new file mode 100644 index 000000000000..9bbe31fbaa6c --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.mock.ts @@ -0,0 +1,17 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + post: { + __typename: 'Post', + id: 42, + title: 'String', + body: 'String', + author: { + create: { + email: 'String9882351', + hashedPassword: 'String', + fullName: 'String', + salt: 'String', + }, + }, + }, +}) diff --git a/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.stories.tsx b/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.stories.tsx new file mode 100644 index 000000000000..37c504847772 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.stories.tsx @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import NewPost from './NewPost' + +const meta: Meta = { + component: NewPost, + tags: ['autodocs'], +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.test.tsx b/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.test.tsx new file mode 100644 index 000000000000..ba36770127e4 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import NewPost from './NewPost' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('NewPost', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Post/Post/Post.mock.ts b/__fixtures__/test-project/web/src/components/Post/Post/Post.mock.ts new file mode 100644 index 000000000000..388a963ee1eb --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/Post/Post.mock.ts @@ -0,0 +1,17 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + post: { + __typename: 'Post', + id: 42, + title: 'String', + body: 'String', + author: { + create: { + email: 'String5383269', + hashedPassword: 'String', + fullName: 'String', + salt: 'String', + }, + }, + }, +}) diff --git a/__fixtures__/test-project/web/src/components/Post/Post/Post.stories.tsx b/__fixtures__/test-project/web/src/components/Post/Post/Post.stories.tsx new file mode 100644 index 000000000000..febfce8ac487 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/Post/Post.stories.tsx @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import Post from './Post' + +const meta: Meta = { + component: Post, + tags: ['autodocs'], +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/components/Post/Post/Post.test.tsx b/__fixtures__/test-project/web/src/components/Post/Post/Post.test.tsx new file mode 100644 index 000000000000..1ca979644b68 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/Post/Post.test.tsx @@ -0,0 +1,15 @@ +import { render } from '@redwoodjs/testing/web' + +import Post from './Post' +import { standard } from './Post.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('Post', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.mock.ts b/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.mock.ts new file mode 100644 index 000000000000..d4d5aec61207 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.mock.ts @@ -0,0 +1,17 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + post: { + __typename: 'Post', + id: 42, + title: 'String', + body: 'String', + author: { + create: { + email: 'String5423599', + hashedPassword: 'String', + fullName: 'String', + salt: 'String', + }, + }, + }, +}) diff --git a/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.stories.tsx b/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.stories.tsx new file mode 100644 index 000000000000..df2621ec5f17 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.stories.tsx @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { Loading, Failure, Success } from './PostCell' +import { standard } from './PostCell.mock' + +const meta: Meta = { + title: 'Cells/PostCell', + tags: ['autodocs'], +} + +export default meta + +export const loading: StoryObj = { + render: () => { + return Loading ? : <> + }, +} + +export const failure: StoryObj = { + render: (args) => { + return Failure ? : <> + }, +} + +export const success: StoryObj = { + render: (args) => { + return Success ? : <> + }, +} diff --git a/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.test.tsx b/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.test.tsx new file mode 100644 index 000000000000..daa1c411bddf --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.test.tsx @@ -0,0 +1,25 @@ +import { render } from '@redwoodjs/testing/web' + +import { Loading, Failure, Success } from './PostCell' +import { standard } from './PostCell.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('PostCell', () => { + it('renders loading successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders failure successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.mock.ts b/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.mock.ts new file mode 100644 index 000000000000..5ad2ab6cb057 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.mock.ts @@ -0,0 +1,17 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + post: { + __typename: 'Post', + id: 42, + title: 'String', + body: 'String', + author: { + create: { + email: 'String427314', + hashedPassword: 'String', + fullName: 'String', + salt: 'String', + }, + }, + }, +}) diff --git a/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.stories.tsx b/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.stories.tsx new file mode 100644 index 000000000000..50c6776e5221 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.stories.tsx @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import PostForm from './PostForm' + +const meta: Meta = { + component: PostForm, + tags: ['autodocs'], +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.test.tsx b/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.test.tsx new file mode 100644 index 000000000000..b46f8508fca5 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import PostForm from './PostForm' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('PostForm', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Post/Posts/Posts.mock.ts b/__fixtures__/test-project/web/src/components/Post/Posts/Posts.mock.ts new file mode 100644 index 000000000000..4e013de27748 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/Posts/Posts.mock.ts @@ -0,0 +1,33 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + posts: [ + { + __typename: 'Post', + id: 42, + title: 'String', + body: 'String', + author: { + create: { + email: 'String4411030', + hashedPassword: 'String', + fullName: 'String', + salt: 'String', + }, + }, + }, + { + __typename: 'Post', + id: 43, + title: 'String', + body: 'String', + author: { + create: { + email: 'String238986', + hashedPassword: 'String', + fullName: 'String', + salt: 'String', + }, + }, + }, + ], +}) diff --git a/__fixtures__/test-project/web/src/components/Post/Posts/Posts.stories.tsx b/__fixtures__/test-project/web/src/components/Post/Posts/Posts.stories.tsx new file mode 100644 index 000000000000..23461e24a2ba --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/Posts/Posts.stories.tsx @@ -0,0 +1,26 @@ +// Pass props to your component by passing an `args` object to your story +// +// ```tsx +// export const Primary: Story = { +// args: { +// propName: propValue +// } +// } +// ``` +// +// See https://storybook.js.org/docs/react/writing-stories/args. + +import type { Meta, StoryObj } from '@storybook/react' + +import Posts from './Posts' + +const meta: Meta = { + component: Posts, + tags: ['autodocs'], +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/components/Post/Posts/Posts.test.tsx b/__fixtures__/test-project/web/src/components/Post/Posts/Posts.test.tsx new file mode 100644 index 000000000000..095858b544d7 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/Posts/Posts.test.tsx @@ -0,0 +1,15 @@ +import { render } from '@redwoodjs/testing/web' + +import Posts from './Posts' +import { standard } from './Posts.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('Posts', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.mock.ts b/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.mock.ts new file mode 100644 index 000000000000..81b05373bea3 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.mock.ts @@ -0,0 +1,33 @@ +// Define your own mock data here: +export const standard = (/* vars, { ctx, req } */) => ({ + posts: [ + { + __typename: 'Post', + id: 42, + title: 'String', + body: 'String', + author: { + create: { + email: 'String1814572', + hashedPassword: 'String', + fullName: 'String', + salt: 'String', + }, + }, + }, + { + __typename: 'Post', + id: 43, + title: 'String', + body: 'String', + author: { + create: { + email: 'String9023600', + hashedPassword: 'String', + fullName: 'String', + salt: 'String', + }, + }, + }, + ], +}) diff --git a/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.stories.tsx b/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.stories.tsx new file mode 100644 index 000000000000..6827f5f5c804 --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.stories.tsx @@ -0,0 +1,35 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { Loading, Empty, Failure, Success } from './PostsCell' +import { standard } from './PostsCell.mock' + +const meta: Meta = { + title: 'Cells/PostsCell', + tags: ['autodocs'], +} + +export default meta + +export const loading: StoryObj = { + render: () => { + return Loading ? : <> + }, +} + +export const failure: StoryObj = { + render: (args) => { + return Failure ? : <> + }, +} + +export const empty: StoryObj = { + render: (args) => { + return Empty ? : <> + }, +} + +export const success: StoryObj = { + render: (args) => { + return Success ? : <> + }, +} diff --git a/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.test.tsx b/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.test.tsx new file mode 100644 index 000000000000..a9ee8429adca --- /dev/null +++ b/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.test.tsx @@ -0,0 +1,30 @@ +import { render } from '@redwoodjs/testing/web' + +import { Loading, Failure, Empty, Success } from './PostsCell' +import { standard } from './PostsCell.mock' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-components + +describe('PostsCell', () => { + it('renders loading successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders failure successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders empty successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/pages/Contact/ContactPage/ContactPage.stories.tsx b/__fixtures__/test-project/web/src/pages/Contact/ContactPage/ContactPage.stories.tsx new file mode 100644 index 000000000000..545d4c7eee3b --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Contact/ContactPage/ContactPage.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import ContactPage from './ContactPage' + +const meta: Meta = { + component: ContactPage, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/pages/Contact/ContactPage/ContactPage.test.tsx b/__fixtures__/test-project/web/src/pages/Contact/ContactPage/ContactPage.test.tsx new file mode 100644 index 000000000000..dca2e65cde0f --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Contact/ContactPage/ContactPage.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import ContactPage from './ContactPage' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('ContactPage', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/pages/Contact/ContactsPage/ContactsPage.stories.tsx b/__fixtures__/test-project/web/src/pages/Contact/ContactsPage/ContactsPage.stories.tsx new file mode 100644 index 000000000000..d71e49216424 --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Contact/ContactsPage/ContactsPage.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import ContactsPage from './ContactsPage' + +const meta: Meta = { + component: ContactsPage, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/pages/Contact/ContactsPage/ContactsPage.test.tsx b/__fixtures__/test-project/web/src/pages/Contact/ContactsPage/ContactsPage.test.tsx new file mode 100644 index 000000000000..ec408cc8ee99 --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Contact/ContactsPage/ContactsPage.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import ContactsPage from './ContactsPage' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('ContactsPage', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/pages/Contact/EditContactPage/EditContactPage.stories.tsx b/__fixtures__/test-project/web/src/pages/Contact/EditContactPage/EditContactPage.stories.tsx new file mode 100644 index 000000000000..29383e96d71a --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Contact/EditContactPage/EditContactPage.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import EditContactPage from './EditContactPage' + +const meta: Meta = { + component: EditContactPage, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/pages/Contact/EditContactPage/EditContactPage.test.tsx b/__fixtures__/test-project/web/src/pages/Contact/EditContactPage/EditContactPage.test.tsx new file mode 100644 index 000000000000..d09d3330ec51 --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Contact/EditContactPage/EditContactPage.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import EditContactPage from './EditContactPage' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('EditContactPage', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/pages/Contact/NewContactPage/NewContactPage.stories.tsx b/__fixtures__/test-project/web/src/pages/Contact/NewContactPage/NewContactPage.stories.tsx new file mode 100644 index 000000000000..362827b65d8f --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Contact/NewContactPage/NewContactPage.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import NewContactPage from './NewContactPage' + +const meta: Meta = { + component: NewContactPage, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/pages/Contact/NewContactPage/NewContactPage.test.tsx b/__fixtures__/test-project/web/src/pages/Contact/NewContactPage/NewContactPage.test.tsx new file mode 100644 index 000000000000..dfd89d5f97a0 --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Contact/NewContactPage/NewContactPage.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import NewContactPage from './NewContactPage' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('NewContactPage', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/pages/Post/EditPostPage/EditPostPage.stories.tsx b/__fixtures__/test-project/web/src/pages/Post/EditPostPage/EditPostPage.stories.tsx new file mode 100644 index 000000000000..396336fa5537 --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Post/EditPostPage/EditPostPage.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import EditPostPage from './EditPostPage' + +const meta: Meta = { + component: EditPostPage, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/pages/Post/EditPostPage/EditPostPage.test.tsx b/__fixtures__/test-project/web/src/pages/Post/EditPostPage/EditPostPage.test.tsx new file mode 100644 index 000000000000..0dd982b3d9ec --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Post/EditPostPage/EditPostPage.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import EditPostPage from './EditPostPage' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('EditPostPage', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/pages/Post/NewPostPage/NewPostPage.stories.tsx b/__fixtures__/test-project/web/src/pages/Post/NewPostPage/NewPostPage.stories.tsx new file mode 100644 index 000000000000..9cbbc87ac8ae --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Post/NewPostPage/NewPostPage.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import NewPostPage from './NewPostPage' + +const meta: Meta = { + component: NewPostPage, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/pages/Post/NewPostPage/NewPostPage.test.tsx b/__fixtures__/test-project/web/src/pages/Post/NewPostPage/NewPostPage.test.tsx new file mode 100644 index 000000000000..e204183f335e --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Post/NewPostPage/NewPostPage.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import NewPostPage from './NewPostPage' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('NewPostPage', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/pages/Post/PostPage/PostPage.stories.tsx b/__fixtures__/test-project/web/src/pages/Post/PostPage/PostPage.stories.tsx new file mode 100644 index 000000000000..439e99f05d9b --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Post/PostPage/PostPage.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import PostPage from './PostPage' + +const meta: Meta = { + component: PostPage, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/pages/Post/PostPage/PostPage.test.tsx b/__fixtures__/test-project/web/src/pages/Post/PostPage/PostPage.test.tsx new file mode 100644 index 000000000000..52d67ee9e5ea --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Post/PostPage/PostPage.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import PostPage from './PostPage' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('PostPage', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/web/src/pages/Post/PostsPage/PostsPage.stories.tsx b/__fixtures__/test-project/web/src/pages/Post/PostsPage/PostsPage.stories.tsx new file mode 100644 index 000000000000..54005d2a10d2 --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Post/PostsPage/PostsPage.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import PostsPage from './PostsPage' + +const meta: Meta = { + component: PostsPage, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/__fixtures__/test-project/web/src/pages/Post/PostsPage/PostsPage.test.tsx b/__fixtures__/test-project/web/src/pages/Post/PostsPage/PostsPage.test.tsx new file mode 100644 index 000000000000..d26d6d174493 --- /dev/null +++ b/__fixtures__/test-project/web/src/pages/Post/PostsPage/PostsPage.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import PostsPage from './PostsPage' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('PostsPage', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) From 1f16d1b091a27f858f3d5d0aefbf44a6ce730a4a Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Thu, 2 Jan 2025 11:51:21 +0700 Subject: [PATCH 15/18] consistent mock values --- .../Post/EditPostCell/EditPostCell.mock.ts | 2 +- .../components/Post/NewPost/NewPost.mock.ts | 2 +- .../web/src/components/Post/Post/Post.mock.ts | 2 +- .../components/Post/PostCell/PostCell.mock.ts | 2 +- .../components/Post/PostForm/PostForm.mock.ts | 2 +- .../src/components/Post/Posts/Posts.mock.ts | 4 +- .../Post/PostsCell/PostsCell.mock.ts | 4 +- .../test-project/codemods/mockValueSuffix.js | 17 +++++++++ tasks/test-project/tui-tasks.js | 37 ++++++++++++++++++- 9 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 tasks/test-project/codemods/mockValueSuffix.js diff --git a/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.mock.ts b/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.mock.ts index 2e72f708b4c0..e5bf9518cc57 100644 --- a/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.mock.ts +++ b/__fixtures__/test-project/web/src/components/Post/EditPostCell/EditPostCell.mock.ts @@ -7,7 +7,7 @@ export const standard = (/* vars, { ctx, req } */) => ({ body: 'String', author: { create: { - email: 'String1253984', + email: 'String10', hashedPassword: 'String', fullName: 'String', salt: 'String', diff --git a/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.mock.ts b/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.mock.ts index 9bbe31fbaa6c..e5bf9518cc57 100644 --- a/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.mock.ts +++ b/__fixtures__/test-project/web/src/components/Post/NewPost/NewPost.mock.ts @@ -7,7 +7,7 @@ export const standard = (/* vars, { ctx, req } */) => ({ body: 'String', author: { create: { - email: 'String9882351', + email: 'String10', hashedPassword: 'String', fullName: 'String', salt: 'String', diff --git a/__fixtures__/test-project/web/src/components/Post/Post/Post.mock.ts b/__fixtures__/test-project/web/src/components/Post/Post/Post.mock.ts index 388a963ee1eb..e5bf9518cc57 100644 --- a/__fixtures__/test-project/web/src/components/Post/Post/Post.mock.ts +++ b/__fixtures__/test-project/web/src/components/Post/Post/Post.mock.ts @@ -7,7 +7,7 @@ export const standard = (/* vars, { ctx, req } */) => ({ body: 'String', author: { create: { - email: 'String5383269', + email: 'String10', hashedPassword: 'String', fullName: 'String', salt: 'String', diff --git a/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.mock.ts b/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.mock.ts index d4d5aec61207..e5bf9518cc57 100644 --- a/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.mock.ts +++ b/__fixtures__/test-project/web/src/components/Post/PostCell/PostCell.mock.ts @@ -7,7 +7,7 @@ export const standard = (/* vars, { ctx, req } */) => ({ body: 'String', author: { create: { - email: 'String5423599', + email: 'String10', hashedPassword: 'String', fullName: 'String', salt: 'String', diff --git a/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.mock.ts b/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.mock.ts index 5ad2ab6cb057..e5bf9518cc57 100644 --- a/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.mock.ts +++ b/__fixtures__/test-project/web/src/components/Post/PostForm/PostForm.mock.ts @@ -7,7 +7,7 @@ export const standard = (/* vars, { ctx, req } */) => ({ body: 'String', author: { create: { - email: 'String427314', + email: 'String10', hashedPassword: 'String', fullName: 'String', salt: 'String', diff --git a/__fixtures__/test-project/web/src/components/Post/Posts/Posts.mock.ts b/__fixtures__/test-project/web/src/components/Post/Posts/Posts.mock.ts index 4e013de27748..9f3bbd24f0a9 100644 --- a/__fixtures__/test-project/web/src/components/Post/Posts/Posts.mock.ts +++ b/__fixtures__/test-project/web/src/components/Post/Posts/Posts.mock.ts @@ -8,7 +8,7 @@ export const standard = (/* vars, { ctx, req } */) => ({ body: 'String', author: { create: { - email: 'String4411030', + email: 'String11', hashedPassword: 'String', fullName: 'String', salt: 'String', @@ -22,7 +22,7 @@ export const standard = (/* vars, { ctx, req } */) => ({ body: 'String', author: { create: { - email: 'String238986', + email: 'String25', hashedPassword: 'String', fullName: 'String', salt: 'String', diff --git a/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.mock.ts b/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.mock.ts index 81b05373bea3..9f3bbd24f0a9 100644 --- a/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.mock.ts +++ b/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.mock.ts @@ -8,7 +8,7 @@ export const standard = (/* vars, { ctx, req } */) => ({ body: 'String', author: { create: { - email: 'String1814572', + email: 'String11', hashedPassword: 'String', fullName: 'String', salt: 'String', @@ -22,7 +22,7 @@ export const standard = (/* vars, { ctx, req } */) => ({ body: 'String', author: { create: { - email: 'String9023600', + email: 'String25', hashedPassword: 'String', fullName: 'String', salt: 'String', diff --git a/tasks/test-project/codemods/mockValueSuffix.js b/tasks/test-project/codemods/mockValueSuffix.js new file mode 100644 index 000000000000..7a6441760819 --- /dev/null +++ b/tasks/test-project/codemods/mockValueSuffix.js @@ -0,0 +1,17 @@ +const stringWithSuffixRegex = /String\d+$/ + +export default (file, api) => { + const j = api.jscodeshift + const root = j(file.source) + + // Replaces the randomly generated value with a consistent one + return root + .find(j.Literal, { type: 'StringLiteral' }) + .forEach((obj) => { + const stringValue = obj.value.value + if (stringWithSuffixRegex.test(stringValue)) { + obj.value.value = `String${obj.value.loc.start.line}` + } + }) + .toSource() +} diff --git a/tasks/test-project/tui-tasks.js b/tasks/test-project/tui-tasks.js index 5958f4633b1a..e999460abf66 100644 --- a/tasks/test-project/tui-tasks.js +++ b/tasks/test-project/tui-tasks.js @@ -23,7 +23,7 @@ const RW_FRAMEWORK_PATH = path.join(__dirname, '../../') function fullPath(name, { addExtension } = { addExtension: true }) { if (addExtension) { - if (name.startsWith('api')) { + if (name.startsWith('api') || name.endsWith('.mock')) { name += '.ts' } else if (name.startsWith('web')) { name += '.tsx' @@ -736,11 +736,44 @@ export default DoublePage` task: async () => { await generateScaffold('post') - // Replace the random numbers in the scenario with consistent values + // Replace the random numbers in the scenario and mocks with consistent + // values await applyCodemod( 'scenarioValueSuffix.js', fullPath('api/src/services/posts/posts.scenarios'), ) + await applyCodemod( + 'mockValueSuffix.js', + fullPath('api/src/services/posts/posts.mock'), + ) + await applyCodemod( + 'mockValueSuffix.js', + fullPath('web/src/components/Post/EditPostCell/EditPostCell.mock'), + ) + await applyCodemod( + 'mockValueSuffix.js', + fullPath('web/src/components/Post/NewPost/NewPost.mock'), + ) + await applyCodemod( + 'mockValueSuffix.js', + fullPath('web/src/components/Post/Post/Post.mock'), + ) + await applyCodemod( + 'mockValueSuffix.js', + fullPath('web/src/components/Post/PostCell/PostCell.mock'), + ) + await applyCodemod( + 'mockValueSuffix.js', + fullPath('web/src/components/Post/PostForm/PostForm.mock'), + ) + await applyCodemod( + 'mockValueSuffix.js', + fullPath('web/src/components/Post/Posts/Posts.mock'), + ) + await applyCodemod( + 'mockValueSuffix.js', + fullPath('web/src/components/Post/PostsCell/PostsCell.mock'), + ) await exec(`yarn rwfw project:copy`, [], execaOptions) }, From af406185564b7c28a75c176d4e0f81cb2cbdb584 Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Fri, 3 Jan 2025 14:19:10 -0600 Subject: [PATCH 16/18] feat: showcase the use of relations --- .../scaffold/templates/components/NamesCell.tsx.template | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx.template b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx.template index 23c15e94bdae..f0d5113b22b3 100644 --- a/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx.template +++ b/packages/cli/src/commands/generate/scaffold/templates/components/NamesCell.tsx.template @@ -15,7 +15,12 @@ export const QUERY: TypedDocumentNode< > = gql` query Find${pluralPascalName} { ${pluralCamelName} {<% columns.forEach(column => { %> - <%= column.name %><% }) %> + <%= column.name %><% }) %><% relations.forEach(relation => { %> + ${relation} { + id + # Add the ${relation} fields you need here + } + <% }) %> } } ` From 21278a56f072d84d2500bd1590030266bc4a874a Mon Sep 17 00:00:00 2001 From: esteban-url <14810250+esteban-url@users.noreply.github.com> Date: Fri, 3 Jan 2025 14:51:10 -0600 Subject: [PATCH 17/18] update snapshots --- .../__snapshots__/scaffold.test.js.snap | 27 +++++++++++++++++++ .../__snapshots__/scaffoldNoNest.test.js.snap | 18 +++++++++++++ 2 files changed, 45 insertions(+) diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffold.test.js.snap b/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffold.test.js.snap index bd869d2346e0..73c804804e35 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffold.test.js.snap +++ b/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffold.test.js.snap @@ -198,6 +198,15 @@ export const QUERY = gql\` upvotes metadata hugeNumber + favorites { + id + # Add the favorites fields you need here + } + + tag { + id + # Add the tag fields you need here + } } } \` @@ -1794,6 +1803,15 @@ export const QUERY = gql\` upvotes metadata hugeNumber + favorites { + id + # Add the favorites fields you need here + } + + tag { + id + # Add the tag fields you need here + } } } \` @@ -3636,6 +3654,15 @@ export const QUERY: TypedDocumentNode = gql\` upvotes metadata hugeNumber + favorites { + id + # Add the favorites fields you need here + } + + tag { + id + # Add the tag fields you need here + } } } \` diff --git a/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffoldNoNest.test.js.snap b/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffoldNoNest.test.js.snap index d2a5999ec2ab..0a39ad3cfe4d 100644 --- a/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffoldNoNest.test.js.snap +++ b/packages/cli/src/commands/generate/scaffold/__tests__/__snapshots__/scaffoldNoNest.test.js.snap @@ -1049,6 +1049,15 @@ export const QUERY = gql\` upvotes metadata hugeNumber + favorites { + id + # Add the favorites fields you need here + } + + tag { + id + # Add the tag fields you need here + } } } \` @@ -2425,6 +2434,15 @@ export const QUERY: TypedDocumentNode = gql\` upvotes metadata hugeNumber + favorites { + id + # Add the favorites fields you need here + } + + tag { + id + # Add the tag fields you need here + } } } \` From 393068e886d2bffa085206e054b7f8fbeea2365d Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Mon, 6 Jan 2025 13:39:06 +0700 Subject: [PATCH 18/18] Update test project --- .../web/src/components/Post/PostsCell/PostsCell.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.tsx b/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.tsx index d7db11c51d06..9c31b1d7c72d 100644 --- a/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.tsx +++ b/__fixtures__/test-project/web/src/components/Post/PostsCell/PostsCell.tsx @@ -17,6 +17,10 @@ export const QUERY: TypedDocumentNode = gql` body authorId createdAt + author { + id + # Add the author fields you need here + } } } `