fix: fix storybook coverage task (#5256)

- Fixes storybook coverage command: the coverage directory path was
incorrect, but instead of failing `storybook:test --configuration=ci`,
it was hanging indefinitely.
- Switches back to `concurrently` to launch `storybook:static` and
`storybook:test` in parallel, which allows to use options to explicitly
kill `storybook:static` when `storybook:test` fails.
- Moves `storybook:test --configuration=ci` to its own command
`storybook:static:test`: used in the CI, and can be used locally to run
storybook tests without having to launch `storybook:dev` first.
- Creates command `storybook:coverage` and enables cache for this
command.
- Fixes Jest tests that were failing.
- Improves caching conditions for some tasks (for instance, no need to
invalidate Jest test cache if only Storybook story files were modified).
This commit is contained in:
Thaïs
2024-05-03 14:59:09 +02:00
committed by GitHub
parent 50421863d4
commit 1351a95754
11 changed files with 123 additions and 75 deletions

View File

@ -24,6 +24,8 @@ runs:
path: | path: |
.cache .cache
.nx/cache .nx/cache
node_modules/.cache
packages/*/node_modules/.cache
key: tasks-cache-${{ github.ref_name }}-${{ inputs.tag }}-${{ steps.tasks-key.outputs.key }}${{ inputs.suffix }}-${{ github.sha }} key: tasks-cache-${{ github.ref_name }}-${{ inputs.tag }}-${{ steps.tasks-key.outputs.key }}${{ inputs.suffix }}-${{ github.sha }}
restore-keys: | restore-keys: |
tasks-cache-${{ github.ref_name }}-${{ inputs.tag }}-${{ steps.tasks-key.outputs.key }}${{ inputs.suffix }}- tasks-cache-${{ github.ref_name }}-${{ inputs.tag }}-${{ steps.tasks-key.outputs.key }}${{ inputs.suffix }}-

View File

@ -62,7 +62,7 @@ jobs:
- name: Front / Write .env - name: Front / Write .env
run: npx nx reset:env twenty-front run: npx nx reset:env twenty-front
- name: Run storybook tests - name: Run storybook tests
run: npx nx storybook:test twenty-front --configuration=ci --scope=${{ matrix.storybook_scope }} run: npx nx storybook:static:test twenty-front --configuration=${{ matrix.storybook_scope }}
front-chromatic-deployment: front-chromatic-deployment:
if: contains(github.event.pull_request.labels.*.name, 'run-chromatic') || github.event_name == 'push' if: contains(github.event.pull_request.labels.*.name, 'run-chromatic') || github.event_name == 'push'
needs: front-sb-build needs: front-sb-build

100
nx.json
View File

@ -1,11 +1,33 @@
{ {
"namedInputs": { "namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"], "default": ["{projectRoot}/**/*"],
"sharedGlobals": ["{workspaceRoot}/.github/workflows/**/*"] "excludeStories": [
"default",
"!{projectRoot}/.storybook/*",
"!{projectRoot}/**/tsconfig.storybook.json",
"!{projectRoot}/**/*.stories.(ts|tsx)",
"!{projectRoot}/**/__stories__/*"
],
"excludeTests": [
"default",
"!{projectRoot}/**/jest.config.(js|ts)",
"!{projectRoot}/**/tsconfig.spec.json",
"!{projectRoot}/**/*.test.(ts|tsx)",
"!{projectRoot}/**/*.spec.(ts|tsx)",
"!{projectRoot}/**/__tests__/*"
],
"production": [
"default",
"excludeStories",
"excludeTests",
"!{projectRoot}/**/__mocks__/*",
"!{projectRoot}/**/testing/*"
]
}, },
"targetDefaults": { "targetDefaults": {
"build": { "build": {
"cache": true, "cache": true,
"inputs": ["^production", "production"],
"dependsOn": ["^build"] "dependsOn": ["^build"]
}, },
"start": { "start": {
@ -58,6 +80,11 @@
"executor": "@nx/jest:jest", "executor": "@nx/jest:jest",
"cache": true, "cache": true,
"dependsOn": ["^build"], "dependsOn": ["^build"],
"inputs": [
"^default",
"excludeStories",
"{workspaceRoot}/jest.preset.js"
],
"outputs": ["{projectRoot}/coverage"], "outputs": ["{projectRoot}/coverage"],
"options": { "options": {
"jestConfig": "{projectRoot}/jest.config.ts", "jestConfig": "{projectRoot}/jest.config.ts",
@ -82,12 +109,7 @@
"executor": "@nx/storybook:build", "executor": "@nx/storybook:build",
"cache": true, "cache": true,
"dependsOn": ["^build"], "dependsOn": ["^build"],
"inputs": [ "inputs": ["^default", "excludeTests"],
"default",
"^default",
"{projectRoot}/.storybook/**/*",
"{projectRoot}/tsconfig.storybook.json"
],
"outputs": ["{options.outputDir}"], "outputs": ["{options.outputDir}"],
"options": { "options": {
"outputDir": "{projectRoot}/storybook-static", "outputDir": "{projectRoot}/storybook-static",
@ -106,37 +128,51 @@
"executor": "@nx/web:file-server", "executor": "@nx/web:file-server",
"options": { "options": {
"staticFilePath": "{projectRoot}/storybook-static", "staticFilePath": "{projectRoot}/storybook-static",
"parallel": false,
"watch": false "watch": false
} }
}, },
"storybook:coverage": {
"executor": "nx:run-commands",
"cache": true,
"inputs": [
"^default",
"excludeTests",
"{projectRoot}/coverage/storybook/coverage-storybook.json"
],
"outputs": [
"{projectRoot}/coverage/storybook",
"!{projectRoot}/coverage/storybook/coverage-storybook.json"
],
"options": {
"command": "npx nyc report --reporter={args.reporter} --reporter=text-summary -t {args.coverageDir} --report-dir {args.coverageDir} --check-coverage --cwd={projectRoot}",
"coverageDir": "coverage/storybook",
"reporter": "lcov"
}
},
"storybook:test": { "storybook:test": {
"executor": "nx:run-commands", "executor": "nx:run-commands",
"cache": true,
"inputs": ["^default", "excludeTests"],
"outputs": ["{projectRoot}/coverage/storybook"],
"options": { "options": {
"cwd": "{projectRoot}",
"commands": [ "commands": [
"test-storybook -c {args.configDir} --url {args.url} --maxWorkers=3 --coverage", "test-storybook --url http://localhost:{args.port} --maxWorkers=3 --coverage --coverageDirectory={args.coverageDir}",
"nyc report --reporter=lcov --reporter=text-summary -t {args.coverageDir} --report-dir {args.coverageDir} --check-coverage" "nx storybook:coverage {projectName} --coverageDir={args.coverageDir}"
], ],
"parallel": false, "parallel": false,
"configDir": "{projectRoot}/.storybook", "coverageDir": "coverage/storybook",
"coverageDir": "{projectRoot}/coverage/storybook", "port": 6006
"url": "http://localhost:6006", }
},
"storybook:static:test": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:static {projectName} --port={args.port}' 'npx wait-on tcp:{args.port} && nx storybook:test {projectName} --port={args.port}'"
],
"port": 6006 "port": 6006
},
"configurations": {
"ci": {
"commands": [
{
"prefix": "[SB]",
"command": "nx storybook:static {projectName} --port={args.port}",
"forwardAllArgs": false
},
{
"command": "npx wait-on tcp:{args.port} && nx storybook:test {projectName}",
"forwardAllArgs": false
}
],
"parallel": true
}
} }
}, },
"chromatic": { "chromatic": {
@ -154,7 +190,11 @@
}, },
"@nx/jest:jest": { "@nx/jest:jest": {
"cache": true, "cache": true,
"inputs": ["default", "^default", "{workspaceRoot}/jest.preset.js"], "inputs": [
"^default",
"excludeStories",
"{workspaceRoot}/jest.preset.js"
],
"options": { "options": {
"passWithNoTests": true "passWithNoTests": true
}, },

View File

@ -1,4 +1,5 @@
const globalCoverage = { const globalCoverage = {
branches: 45,
statements: 60, statements: 60,
lines: 60, lines: 60,
functions: 60, functions: 60,
@ -6,6 +7,7 @@ const globalCoverage = {
}; };
const modulesCoverage = { const modulesCoverage = {
branches: 45,
statements: 70, statements: 70,
lines: 70, lines: 70,
functions: 65, functions: 65,
@ -14,6 +16,7 @@ const modulesCoverage = {
}; };
const pagesCoverage = { const pagesCoverage = {
branches: 45,
statements: 60, statements: 60,
lines: 60, lines: 60,
functions: 45, functions: 45,

View File

@ -63,13 +63,12 @@
"storybook:build:scope": { "storybook:build:scope": {
"executor": "nx:run-commands", "executor": "nx:run-commands",
"options": { "options": {
"command": "STORYBOOK_SCOPE={args.scope} nx storybook:build twenty-front", "command": "nx storybook:build twenty-front"
"scope": "all"
}, },
"configurations": { "configurations": {
"docs": { "scope": "ui-docs" }, "docs": { "env": { "STORYBOOK_SCOPE": "ui-docs" } },
"modules": { "scope": "modules" }, "modules": { "env": { "STORYBOOK_SCOPE": "modules" } },
"pages": { "scope": "pages" } "pages": { "env": { "STORYBOOK_SCOPE": "pages" } }
} }
}, },
"storybook:dev": { "storybook:dev": {
@ -78,13 +77,12 @@
"storybook:dev:scope": { "storybook:dev:scope": {
"executor": "nx:run-commands", "executor": "nx:run-commands",
"options": { "options": {
"command": "STORYBOOK_SCOPE={args.scope} nx storybook:dev twenty-front", "command": "nx storybook:dev twenty-front"
"scope": "all"
}, },
"configurations": { "configurations": {
"docs": { "scope": "ui-docs" }, "docs": { "env": { "STORYBOOK_SCOPE": "ui-docs" } },
"modules": { "scope": "modules" }, "modules": { "env": { "STORYBOOK_SCOPE": "modules" } },
"pages": { "scope": "pages" } "pages": { "env": { "STORYBOOK_SCOPE": "pages" } }
} }
}, },
"storybook:static": { "storybook:static": {
@ -96,35 +94,39 @@
"storybook:static:scope": { "storybook:static:scope": {
"executor": "nx:run-commands", "executor": "nx:run-commands",
"options": { "options": {
"command": "STORYBOOK_SCOPE={args.scope} nx storybook:static twenty-front", "command": "nx storybook:static twenty-front"
"scope": "all"
}, },
"configurations": { "configurations": {
"docs": { "scope": "ui-docs" }, "docs": { "env": { "STORYBOOK_SCOPE": "ui-docs" } },
"modules": { "scope": "modules" }, "modules": { "env": { "STORYBOOK_SCOPE": "modules" } },
"pages": { "scope": "pages" } "pages": { "env": { "STORYBOOK_SCOPE": "pages" } }
}
},
"storybook:coverage": {
"configurations": {
"docs": { "env": { "STORYBOOK_SCOPE": "ui-docs" } },
"modules": { "env": { "STORYBOOK_SCOPE": "modules" } },
"pages": { "env": { "STORYBOOK_SCOPE": "pages" } }
} }
}, },
"storybook:test": { "storybook:test": {
"options": { "options": {
"url": "http://localhost:6006",
"port": 6006 "port": 6006
}, },
"configurations": { "configurations": {
"ci": { "docs": { "env": { "STORYBOOK_SCOPE": "ui-docs" } },
"commands": [ "modules": { "env": { "STORYBOOK_SCOPE": "modules" } },
{ "pages": { "env": { "STORYBOOK_SCOPE": "pages" } }
"prefix": "[SB]", }
"command": "nx storybook:static {projectName} --port={args.port}", },
"forwardAllArgs": false "storybook:static:test": {
}, "options": {
{ "commands": [
"command": "STORYBOOK_SCOPE={args.scope} npx wait-on tcp:{args.port} && nx storybook:test {projectName}", "npx concurrently --kill-others --success=first -n SB,TEST 'nx storybook:static {projectName} --port={args.port}' 'npx wait-on tcp:{args.port} && nx storybook:test {projectName} --port={args.port} --configuration={args.scope}'"
"forwardAllArgs": false ],
} "port": 6006
], },
"parallel": true "configurations": {
},
"docs": { "scope": "ui-docs" }, "docs": { "scope": "ui-docs" },
"modules": { "scope": "modules" }, "modules": { "scope": "modules" },
"pages": { "scope": "pages" } "pages": { "scope": "pages" }

View File

@ -62,8 +62,8 @@ describe('generateCsv', () => {
}, },
]; ];
const csv = generateCsv({ columns, rows }); const csv = generateCsv({ columns, rows });
expect(csv).toEqual(`Foo,Empty,Nested Foo,Nested Nested expect(csv).toEqual(`Foo,Empty,Nested Foo,Nested Nested,Relation
some field,,foo,nested`); some field,,foo,nested,a relation`);
}); });
}); });

View File

@ -36,14 +36,16 @@ export const generateCsv: GenerateExport = ({
}: GenerateExportOptions): string => { }: GenerateExportOptions): string => {
const columnsToExport = columns.filter( const columnsToExport = columns.filter(
(col) => (col) =>
!('relationType' in col.metadata && col.metadata.relationType) || !('relationType' in col.metadata) ||
col.metadata.relationType === 'TO_ONE_OBJECT', col.metadata.relationType === 'TO_ONE_OBJECT',
); );
const keys = columnsToExport.flatMap((col) => { const keys = columnsToExport.flatMap((col) => {
const column = { const column = {
field: `${col.metadata.fieldName}${col.type === 'RELATION' ? 'Id' : ''}`, field: `${col.metadata.fieldName}${col.type === 'RELATION' ? 'Id' : ''}`,
title: `${col.label} ${col.type === 'RELATION' ? 'Id' : ''}`, title: [col.label, col.type === 'RELATION' ? 'Id' : null]
.filter(isDefined)
.join(' '),
}; };
const fieldsWithSubFields = rows.find((row) => { const fieldsWithSubFields = rows.find((row) => {

View File

@ -2,6 +2,7 @@ import { useNavigate } from 'react-router-dom';
import { Section } from '@react-email/components'; import { Section } from '@react-email/components';
import { useDeleteOneDatabaseConnection } from '@/databases/hooks/useDeleteOneDatabaseConnection'; import { useDeleteOneDatabaseConnection } from '@/databases/hooks/useDeleteOneDatabaseConnection';
import { SettingsIntegrationDatabaseConnectionSummaryCard } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionSummaryCard';
import { SettingsIntegrationDatabaseTablesListCard } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseTablesListCard'; import { SettingsIntegrationDatabaseTablesListCard } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseTablesListCard';
import { useDatabaseConnection } from '@/settings/integrations/database-connection/hooks/useDatabaseConnection'; import { useDatabaseConnection } from '@/settings/integrations/database-connection/hooks/useDatabaseConnection';
import { getConnectionDbName } from '@/settings/integrations/utils/getConnectionDbName'; import { getConnectionDbName } from '@/settings/integrations/utils/getConnectionDbName';
@ -9,7 +10,6 @@ import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath'; import { SettingsPath } from '@/types/SettingsPath';
import { H2Title } from '@/ui/display/typography/components/H2Title'; import { H2Title } from '@/ui/display/typography/components/H2Title';
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
import { SettingsIntegrationDatabaseConnectionSummaryCard } from '~/pages/settings/integrations/SettingsIntegrationDatabaseConnectionSummaryCard';
export const SettingsIntegrationDatabaseConnectionShowContainer = () => { export const SettingsIntegrationDatabaseConnectionShowContainer = () => {
const navigate = useNavigate(); const navigate = useNavigate();

View File

@ -1,4 +1,5 @@
import { import {
FieldMetadataType,
ObjectEdge, ObjectEdge,
ObjectMetadataItemsQuery, ObjectMetadataItemsQuery,
} from '~/generated-metadata/graphql'; } from '~/generated-metadata/graphql';
@ -3201,7 +3202,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
node: { node: {
__typename: 'field', __typename: 'field',
id: '7ada51cb-58be-42cd-86df-16c3f2bb8b58', id: '7ada51cb-58be-42cd-86df-16c3f2bb8b58',
type: 'TEXT', type: FieldMetadataType.Phone,
name: 'phone', name: 'phone',
label: 'Phone', label: 'Phone',
description: 'Contacts phone number', description: 'Contacts phone number',

View File

@ -11,11 +11,7 @@
"generateBarrels": { "generateBarrels": {
"executor": "nx:run-commands", "executor": "nx:run-commands",
"cache": true, "cache": true,
"inputs": [ "inputs": ["production", "{projectRoot}/scripts/generateBarrels.js"],
"{projectRoot}/src/**/*.{ts,tsx}",
"!{projectRoot}/src/**/*.(spec|test).{ts,tsx}",
"!{projectRoot}/src/**/*.stories.{ts,tsx}"
],
"outputs": ["{projectRoot}/src/index.ts", "{projectRoot}/src/*/index.ts"], "outputs": ["{projectRoot}/src/index.ts", "{projectRoot}/src/*/index.ts"],
"options": { "options": {
"command": "node {projectRoot}/scripts/generateBarrels.js" "command": "node {projectRoot}/scripts/generateBarrels.js"
@ -52,10 +48,12 @@
"port": 6007 "port": 6007
} }
}, },
"storybook:coverage": {},
"storybook:test": { "storybook:test": {
"options": { "options": { "port": 6007 }
"url": "http://localhost:6007" },
} "storybook:static:test": {
"options": { "port": 6007 }
} }
} }
} }