diff --git a/.editorconfig b/.editorconfig index 4787390e5..671f546b8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,11 +5,8 @@ charset = utf-8 end_of_line = lf indent_size = 4 indent_style = space -insert_final_newline = false +insert_final_newline = true max_line_length = 120 -[*.{js,jsx,ejs,mjs,ts,tsx,json,css,yaml}] -indent_size = 2 - -[Makefile] -indent_style = tab +[*.{js,ejs,cjs,mjs,ts,jsx,tsx,json,css,less,yml,yaml}] +indent_size = 2 \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..83464d16a --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,40 @@ +module.exports = { + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:vitest/recommended', + 'plugin:vitest-globals/recommended', + 'plugin:cypress/recommended', + 'prettier', + ], + parser: '@typescript-eslint/parser', + plugins: ['react', 'react-hooks', 'import', '@typescript-eslint', 'vitest', 'cypress'], + globals: { + fetchMock: true, + vi: true, + FormioUtils: true, + }, + env: { + 'vitest-globals/env': true, + 'cypress/globals': true, + }, + rules: { + 'no-unused-labels': 'error', // Should not have any unused labels + 'import/no-duplicates': 'error', // Should not import the same module twice (should be handled automatically by prettier-plugin-organize-imports) + '@typescript-eslint/no-unused-vars': ['warn', { ignoreRestSiblings: true, argsIgnorePattern: '^[_$].*' }], // ignores unused variables starting with _ or $ + '@typescript-eslint/ban-types': 'off', // TODO: Remove 'Function' as a type mostly + '@typescript-eslint/no-explicit-any': 'off', // Explicit any's + '@typescript-eslint/ban-ts-comment': 'off', // @ts-ignore and @ts-nocheck comments + '@typescript-eslint/no-namespace': 'off', // TODO: FormSummaryType.ts has a Summary namespace + 'no-extra-boolean-cast': 'off', // TODO: Remove redudant "!!" + 'no-case-declarations': 'off', // TODO: Remove "let/const" in switch cases + 'vitest/expect-expect': 'off', // Cypress tests don't necessarily use expect + 'react/jsx-key': ['error', { checkFragmentShorthand: true }], // There was an error with a missing key that crashed the app + 'import/no-internal-modules': [ + 'error', + { forbid: ['@navikt/skjemadigitalisering-shared-@(components|domain)/**'] }, + ], // Should not import from shared components or domain + }, + root: true, +}; diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 32f0b9466..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:vitest/recommended", - "plugin:vitest-globals/recommended", - "plugin:cypress/recommended" - ], - "plugins": ["react", "react-hooks", "import", "@typescript-eslint", "vitest", "cypress"], - "globals": { - "fetchMock": true, - "vi": true, - "FormioUtils": true - }, - "env": { - "vitest-globals/env": true, - "cypress/globals": true - }, - "rules": { - "no-unused-labels": "error", - "no-unused-vars": "off", - "import/no-duplicates": "error", - "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], - "@typescript-eslint/ban-types": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-non-null-asserted-optional-chain": "off", - "@typescript-eslint/no-inferrable-types": "off", - "@typescript-eslint/no-namespace": "off", - "no-extra-boolean-cast": "off", - "no-case-declarations": "off", - "vitest/prefer-to-be": "off", - "vitest/no-identical-title": "off", - "vitest/valid-expect": "off", - "vitest/valid-title": "off", - "vitest/expect-expect": "off", - "cypress/unsafe-to-chain-command": "off", - "react/jsx-key": ["error", { "checkFragmentShorthand": true }], - "import/no-internal-modules": [ - "error", - { - "forbid": ["@navikt/skjemadigitalisering-shared-@(components|domain)/**"] - } - ] - }, - "root": true -} diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index abb452780..cefd9aa25 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -1,29 +1,29 @@ version: 2 updates: - - package-ecosystem: "npm" - directory: "/" + - package-ecosystem: 'npm' + directory: '/' schedule: - interval: "monthly" + interval: 'monthly' versioning-strategy: increase open-pull-requests-limit: 20 groups: navikt: patterns: - - "@navikt/*" + - '@navikt/*' all-minor-patch: patterns: - - "*" + - '*' update-types: - - "minor" - - "patch" + - 'minor' + - 'patch' ignore: - - dependency-name: "formiojs" + - dependency-name: 'formiojs' - - package-ecosystem: "github-actions" - directory: "/" + - package-ecosystem: 'github-actions' + directory: '/' schedule: - interval: "monthly" + interval: 'monthly' groups: all: patterns: - - "*" + - '*' diff --git a/.github/workflows/alert-deploy.yaml b/.github/workflows/alert-deploy.yaml index 659b4d990..d6f9a732e 100644 --- a/.github/workflows/alert-deploy.yaml +++ b/.github/workflows/alert-deploy.yaml @@ -6,10 +6,10 @@ on: branches: - master paths: - - "packages/bygger/.nais/alerts.yaml" - - "packages/bygger/.nais/preprod.yaml" - - "packages/bygger/.nais/prod.yaml" - - ".github/workflows/alert-deploy.yaml" + - 'packages/bygger/.nais/alerts.yaml' + - 'packages/bygger/.nais/preprod.yaml' + - 'packages/bygger/.nais/prod.yaml' + - '.github/workflows/alert-deploy.yaml' jobs: preprod-deploy: name: Deploy to preprod @@ -22,8 +22,8 @@ jobs: env: APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} CLUSTER: dev-gcp - RESOURCE: "./packages/bygger/.nais/alerts.yaml" - VARS: "./packages/bygger/.nais/preprod.yaml" + RESOURCE: './packages/bygger/.nais/alerts.yaml' + VARS: './packages/bygger/.nais/preprod.yaml' prod-deploy: name: Deploy to prod @@ -36,5 +36,5 @@ jobs: env: APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} CLUSTER: prod-gcp - RESOURCE: "./packages/bygger/.nais/alerts.yaml" - VARS: "./packages/bygger/.nais/prod.yaml" \ No newline at end of file + RESOURCE: './packages/bygger/.nais/alerts.yaml' + VARS: './packages/bygger/.nais/prod.yaml' diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index 2a098fed3..f199daf92 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -7,50 +7,50 @@ concurrency: deploy-${{ github.ref }} jobs: build-and-test: - name: "Build and test packages" + name: 'Build and test packages' runs-on: ubuntu-latest-8-cores permissions: - contents: "read" - packages: "read" + contents: 'read' + packages: 'read' steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: "18.16.1" - cache: "yarn" - cache-dependency-path: "**/yarn.lock" + node-version: '20.8.0' + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' registry-url: https://npm.pkg.github.com/ - scope: "@navikt" - - name: "Install dependencies" + scope: '@navikt' + - name: 'Install dependencies' run: yarn --frozen-lockfile - - name: "No unstaged changes allowed (changes in yarn.lock?)" + - name: 'No unstaged changes allowed (changes in yarn.lock?)' run: git diff --quiet - - name: "Check types" + - name: 'Check types' run: yarn check-types - - name: "Build" + - name: 'Build' run: yarn build - - name: "Test" + - name: 'Test' run: yarn test package-and-push-bygger: if: github.ref == 'refs/heads/master' - name: "Package bygger" + name: 'Package bygger' runs-on: ubuntu-latest-8-cores permissions: - contents: "read" - id-token: "write" - packages: "read" + contents: 'read' + id-token: 'write' + packages: 'read' steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: "18.16.1" - cache: "yarn" - cache-dependency-path: "**/yarn.lock" + node-version: '20.8.0' + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' registry-url: https://npm.pkg.github.com/ - scope: "@navikt" + scope: '@navikt' - - name: "Build application: Bygger" + - name: 'Build application: Bygger' env: VITE_GIT_VERSION: ${{ github.sha }} run: yarn --frozen-lockfile && yarn build @@ -72,28 +72,28 @@ jobs: package-and-push-fyllut-base: if: github.ref == 'refs/heads/master' - name: "Package fyllut" + name: 'Package fyllut' runs-on: ubuntu-latest-8-cores permissions: - contents: "read" - id-token: "write" - packages: "read" + contents: 'read' + id-token: 'write' + packages: 'read' steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: "18.16.1" - cache: "yarn" - cache-dependency-path: "**/yarn.lock" + node-version: '20.8.0' + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' registry-url: https://npm.pkg.github.com/ - scope: "@navikt" + scope: '@navikt' - - name: "Build application: Fyllut" + - name: 'Build application: Fyllut' env: VITE_GIT_VERSION: ${{ github.sha }} run: yarn --frozen-lockfile && yarn build - - name: "Build and push Docker image: fyllut-base-dev" + - name: 'Build and push Docker image: fyllut-base-dev' uses: nais/docker-build-push@v0 id: docker-build-push-dev with: @@ -108,7 +108,7 @@ jobs: pull: true tag: ${{ github.sha }} - - name: "Build and push Docker image: fyllut-base" + - name: 'Build and push Docker image: fyllut-base' if: github.ref == 'refs/heads/master' uses: nais/docker-build-push@v0 id: docker-build-push @@ -125,27 +125,27 @@ jobs: tag: ${{ github.sha }} deploy-bygger-to-prod: - name: "Deploy bygger to prod" + name: 'Deploy bygger to prod' if: github.ref == 'refs/heads/master' needs: [build-and-test, package-and-push-bygger, package-and-push-fyllut-base] runs-on: ubuntu-latest steps: - - uses: "actions/checkout@v3" - - name: "Deploy to PROD" - uses: "nais/deploy/actions/deploy@v1" + - uses: 'actions/checkout@v3' + - name: 'Deploy to PROD' + uses: 'nais/deploy/actions/deploy@v1' env: - APIKEY: "${{ secrets.NAIS_DEPLOY_APIKEY }}" - CLUSTER: "prod-gcp" - RESOURCE: "./packages/bygger/.nais/nais.yaml" - VARS: "./packages/bygger/.nais/prod.yaml" - VAR: "image=${{ needs.package-and-push-bygger.outputs.image }}" + APIKEY: '${{ secrets.NAIS_DEPLOY_APIKEY }}' + CLUSTER: 'prod-gcp' + RESOURCE: './packages/bygger/.nais/nais.yaml' + VARS: './packages/bygger/.nais/prod.yaml' + VAR: 'image=${{ needs.package-and-push-bygger.outputs.image }}' trigger-deploy-fyllut-to-dev: - name: "Trigger deploy fyllut to dev" + name: 'Trigger deploy fyllut to dev' needs: [build-and-test, package-and-push-bygger, package-and-push-fyllut-base] runs-on: ubuntu-latest steps: - - name: "Generate app installation access token" + - name: 'Generate app installation access token' uses: navikt/github-app-token-generator@v1 id: generate-token with: @@ -153,11 +153,11 @@ jobs: app-id: ${{ secrets.PUBLISHING_APP_ID }} repo: navikt/skjemautfylling-formio - - name: "Trigger deploy fyllut to dev" + - name: 'Trigger deploy fyllut to dev' uses: benc-uk/workflow-dispatch@v1 with: - workflow: "Trigger dev deploy" + workflow: 'Trigger dev deploy' repo: navikt/skjemautfylling-formio - ref: "dev-deploy" + ref: 'dev-deploy' token: ${{ steps.generate-token.outputs.token }} inputs: '{ "monorepoGitHash": "${{ github.sha }}" }' diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 28d20821c..22bf4be82 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -9,14 +9,14 @@ # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # -name: "CodeQL" +name: 'CodeQL' on: push: - branches: [ master ] + branches: [master] pull_request: # The branches below must be a subset of the branches above - branches: [ master ] + branches: [master] schedule: - cron: '31 1 * * 6' @@ -32,40 +32,40 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'javascript'] + language: ['javascript'] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v3 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/cypress-tests.yaml b/.github/workflows/cypress-tests.yaml index afc5f09db..68e35364a 100644 --- a/.github/workflows/cypress-tests.yaml +++ b/.github/workflows/cypress-tests.yaml @@ -8,26 +8,26 @@ jobs: cypress-run-fyllut: runs-on: ubuntu-latest-8-cores permissions: - contents: "read" + contents: 'read' packages: read steps: - - name: "Checkout" + - name: 'Checkout' uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: "18.16.1" + node-version: '20.8.0' registry-url: https://npm.pkg.github.com/ - scope: "@navikt" - - name: "Install dependencies" + scope: '@navikt' + - name: 'Install dependencies' run: yarn --frozen-lockfile - - name: "Build application" + - name: 'Build application' run: yarn build - - name: "Cypress tests (fyllut)" + - name: 'Cypress tests (fyllut)' uses: cypress-io/github-action@v5 with: install: false start: yarn preview:fyllut - wait-on: "http://localhost:3001/fyllut/internal/isready" + wait-on: 'http://localhost:3001/fyllut/internal/isready' wait-on-timeout: 120 command: yarn cypress:fyllut config: video=false @@ -35,27 +35,27 @@ jobs: cypress-run-bygger: runs-on: ubuntu-latest-8-cores permissions: - contents: "read" + contents: 'read' packages: read steps: - - name: "Checkout" + - name: 'Checkout' uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: "18.16.1" + node-version: '20.8.0' registry-url: https://npm.pkg.github.com/ - scope: "@navikt" - - name: "Install dependencies" + scope: '@navikt' + - name: 'Install dependencies' run: yarn --frozen-lockfile - - name: "Build application" + - name: 'Build application' run: yarn build - - name: "Cypress tests (bygger)" + - name: 'Cypress tests (bygger)' uses: cypress-io/github-action@v5 with: install: false start: yarn preview:bygger - wait-on: "http://localhost:3000/internal/isready" + wait-on: 'http://localhost:3000/internal/isready' wait-on-timeout: 120 command: yarn cypress:bygger config: video=false - config-file: cypress.config.ts \ No newline at end of file + config-file: cypress.config.ts diff --git a/.github/workflows/jest-coverage-report.yaml b/.github/workflows/jest-coverage-report.yaml index 327a23804..9ddd96c86 100644 --- a/.github/workflows/jest-coverage-report.yaml +++ b/.github/workflows/jest-coverage-report.yaml @@ -1,4 +1,4 @@ -name: "Test coverage" +name: 'Test coverage' on: pull_request: branches: [master] @@ -7,19 +7,19 @@ env: jobs: test-coverage: permissions: - contents: "read" + contents: 'read' packages: read runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: "18.16.1" - cache: "yarn" - cache-dependency-path: "**/yarn.lock" + node-version: '20.8.0' + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' registry-url: https://npm.pkg.github.com/ - scope: "@navikt" - - name: "Install dependencies" + scope: '@navikt' + - name: 'Install dependencies' run: yarn - - name: "Test with coverage report" + - name: 'Test with coverage report' run: yarn test:coverage diff --git a/.github/workflows/manual-deploy.yaml b/.github/workflows/manual-deploy.yaml index eec0e3c97..c2b591702 100644 --- a/.github/workflows/manual-deploy.yaml +++ b/.github/workflows/manual-deploy.yaml @@ -4,9 +4,9 @@ on: workflow_dispatch: inputs: environment: - description: "Target environment" + description: 'Target environment' required: true - default: "preprod" + default: 'preprod' type: choice options: - preprod @@ -16,28 +16,28 @@ env: jobs: package-and-push-bygger: - name: "Package bygger" + name: 'Package bygger' runs-on: ubuntu-latest-8-cores permissions: - contents: "read" - id-token: "write" - packages: "read" + contents: 'read' + id-token: 'write' + packages: 'read' steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: "18.16.1" - cache: "yarn" - cache-dependency-path: "**/yarn.lock" + node-version: '20.8.0' + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' registry-url: https://npm.pkg.github.com/ - scope: "@navikt" - - name: "Build application: Bygger" + scope: '@navikt' + - name: 'Build application: Bygger' env: VITE_GIT_VERSION: ${{ github.sha }} VITE_GIT_BRANCH: ${{ github.ref_name }} run: yarn --frozen-lockfile && yarn build - - name: "Build and push Docker image for bygger" + - name: 'Build and push Docker image for bygger' uses: nais/docker-build-push@v0 id: docker-build-push-bygger with: @@ -54,44 +54,44 @@ jobs: image: ${{ steps.docker-build-push-bygger.outputs.image }} deploy-bygger-to-preprod: - name: "Deploy bygger to preprod" + name: 'Deploy bygger to preprod' needs: [package-and-push-bygger] if: ${{ !failure() && !cancelled() }} runs-on: ubuntu-latest steps: - - uses: "actions/checkout@v3" - - name: "Deploy to preprod" - uses: "nais/deploy/actions/deploy@v1" + - uses: 'actions/checkout@v3' + - name: 'Deploy to preprod' + uses: 'nais/deploy/actions/deploy@v1' env: - APIKEY: "${{ secrets.NAIS_DEPLOY_APIKEY }}" - CLUSTER: "dev-gcp" - RESOURCE: "./packages/bygger/.nais/nais.yaml" - VARS: "./packages/bygger/.nais/${{ github.event.inputs.environment }}.yaml" + APIKEY: '${{ secrets.NAIS_DEPLOY_APIKEY }}' + CLUSTER: 'dev-gcp' + RESOURCE: './packages/bygger/.nais/nais.yaml' + VARS: './packages/bygger/.nais/${{ github.event.inputs.environment }}.yaml' VAR: image=${{ needs.package-and-push-bygger.outputs.image }} package-and-push-fyllut: - name: "Package fyllut" + name: 'Package fyllut' runs-on: ubuntu-latest-8-cores permissions: - contents: "read" - id-token: "write" - packages: "read" + contents: 'read' + id-token: 'write' + packages: 'read' steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: "18.16.1" - cache: "yarn" - cache-dependency-path: "**/yarn.lock" + node-version: '20.8.0' + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' registry-url: https://npm.pkg.github.com/ - scope: "@navikt" - - name: "Build application: Fyllut" + scope: '@navikt' + - name: 'Build application: Fyllut' env: VITE_GIT_VERSION: ${{ github.sha }} VITE_GIT_BRANCH: ${{ github.ref_name }} run: yarn --frozen-lockfile && yarn build - - name: "Build and push Docker image for fyllut" + - name: 'Build and push Docker image for fyllut' uses: nais/docker-build-push@v0 id: docker-build-push-fyllut with: @@ -108,17 +108,17 @@ jobs: image: ${{ steps.docker-build-push-fyllut.outputs.image }} deploy-fyllut-to-preprod: - name: "Deploy fyllut to preprod" + name: 'Deploy fyllut to preprod' needs: [package-and-push-fyllut] if: ${{ !failure() && !cancelled() }} runs-on: ubuntu-latest steps: - - uses: "actions/checkout@v3" - - name: "Deploy to preprod" - uses: "nais/deploy/actions/deploy@v1" + - uses: 'actions/checkout@v3' + - name: 'Deploy to preprod' + uses: 'nais/deploy/actions/deploy@v1' env: - APIKEY: "${{ secrets.NAIS_DEPLOY_APIKEY }}" - CLUSTER: "dev-gcp" - RESOURCE: "./packages/fyllut/.nais/config.yaml" - VARS: "./packages/fyllut/.nais/${{ github.event.inputs.environment }}.yaml" + APIKEY: '${{ secrets.NAIS_DEPLOY_APIKEY }}' + CLUSTER: 'dev-gcp' + RESOURCE: './packages/fyllut/.nais/config.yaml' + VARS: './packages/fyllut/.nais/${{ github.event.inputs.environment }}.yaml' VAR: image=${{ needs.package-and-push-fyllut.outputs.image }} diff --git a/.nvmrc b/.nvmrc index 5e0828ad1..a9b234d51 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v18.16.1 +v20.8.0 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..16b08de6a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,5 @@ +package-lock.json + +# Ignore yaml files because it contains handlebars logic +**/.nais/*.yaml +**/.nais/*.yml \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..4e081e407 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "trailingComma": "all", + "semi": true, + "singleQuote": true, + "plugins": ["prettier-plugin-organize-imports"] +} diff --git a/LICENSE.md b/LICENSE.md index b3f0a938b..5aae48736 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -2,7 +2,7 @@ Copyright 2020 NAV (Arbeids- og velferdsdirektoratet) - The Norwegian Labour and Welfare Administration -The contents of the template folder is based on https://github.com/formio/semantic, see [ORIGINAL_LICENSE](./template/ORIGINAL_LICENSE) +The contents of the template folder is based on https://github.com/formio/semantic, see [ORIGINAL_LICENSE](./template/ORIGINAL_LICENSE) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/bin/deploy-context.mjs b/bin/deploy-context.mjs index 047960af9..b17fdcefc 100755 --- a/bin/deploy-context.mjs +++ b/bin/deploy-context.mjs @@ -12,43 +12,41 @@ const replaceFiles = args.indexOf('--replace') > -1; const dryRun = args.indexOf('--dry') > -1; const sharedPackages = [ - {name: "@navikt/skjemadigitalisering-shared-components", path: 'packages/shared-components'}, - {name: "@navikt/skjemadigitalisering-shared-domain", path: 'packages/shared-domain'} + { name: '@navikt/skjemadigitalisering-shared-components', path: 'packages/shared-components' }, + { name: '@navikt/skjemadigitalisering-shared-domain', path: 'packages/shared-domain' }, ]; -sharedPackages.forEach(packageSpec => { - packageSpec.fileDep = "file:" + path.relative(packagePath, path.join(root, packageSpec.path)) +sharedPackages.forEach((packageSpec) => { + packageSpec.fileDep = 'file:' + path.relative(packagePath, path.join(root, packageSpec.path)); }); const packageJsonFilename = path.join(packagePath, 'package.json'); const yarnLockFilename = path.join(packagePath, 'yarn.lock'); -const jsonDataString = fs.readFileSync( - packageJsonFilename, - {encoding: 'utf-8', flag: 'r'}); +const jsonDataString = fs.readFileSync(packageJsonFilename, { encoding: 'utf-8', flag: 'r' }); const packageJson = JSON.parse(jsonDataString); const deps = packageJson.dependencies || {}; -const presentSharedPackages = sharedPackages.filter(packageSpec => packageSpec.name in deps); +const presentSharedPackages = sharedPackages.filter((packageSpec) => packageSpec.name in deps); if (presentSharedPackages.length === 0) { console.log(`Skipping package '${packageJson.name}', does not depend on shared package`); process.exit(0); } function generateNewDeps(deps) { - const newDeps = {...deps}; - presentSharedPackages.forEach((packageSpec) => { - const depValue = newDeps[packageSpec.name]; - console.log(`- ${packageSpec.name}: ${depValue} -> ${packageSpec.fileDep}`); - newDeps[packageSpec.name] = packageSpec.fileDep; - }); - return newDeps; + const newDeps = { ...deps }; + presentSharedPackages.forEach((packageSpec) => { + const depValue = newDeps[packageSpec.name]; + console.log(`- ${packageSpec.name}: ${depValue} -> ${packageSpec.fileDep}`); + newDeps[packageSpec.name] = packageSpec.fileDep; + }); + return newDeps; } function generateNewYarnLock(deps) { - const result = []; - presentSharedPackages.forEach(packageSpec => { - const depValue = deps[packageSpec.name]; - result.push(`"${packageSpec.name}@${packageSpec.fileDep}":\n version "${depValue}"`); - }); - return result; + const result = []; + presentSharedPackages.forEach((packageSpec) => { + const depValue = deps[packageSpec.name]; + result.push(`"${packageSpec.name}@${packageSpec.fileDep}":\n version "${depValue}"`); + }); + return result; } function writeNewFile(filename, fileContent) { @@ -66,23 +64,26 @@ function replaceFile(filename) { console.log(`Processing package '${packageJson.name}'${dryRun ? ' [dry-run]' : ''}:`); const newDeps = generateNewDeps(deps); -const packageJsonContent = JSON.stringify({ - ...packageJson, - dependencies: newDeps -}, null, 2) + '\n'; +const packageJsonContent = + JSON.stringify( + { + ...packageJson, + dependencies: newDeps, + }, + null, + 2, + ) + '\n'; writeNewFile(packageJsonFilename + '.new', packageJsonContent); if (replaceFiles) { replaceFile(packageJsonFilename); console.log(`- moved original package.json file to *.backup, and replaced it with *.new`); } - const newLockEntries = generateNewYarnLock(deps); -const lockContent = fs.readFileSync(yarnLockFilename, {encoding: 'utf-8', flag: 'r'}); -const updatedLockContent = lockContent + "\n" + newLockEntries.join("\n\n"); -writeNewFile(yarnLockFilename + '.new', updatedLockContent) +const lockContent = fs.readFileSync(yarnLockFilename, { encoding: 'utf-8', flag: 'r' }); +const updatedLockContent = lockContent + '\n' + newLockEntries.join('\n\n'); +writeNewFile(yarnLockFilename + '.new', updatedLockContent); if (replaceFiles) { replaceFile(yarnLockFilename); console.log(`- moved original yarn.lock file to *.backup, and replaced it with *.new`); } - diff --git a/bin/package-locator.mjs b/bin/package-locator.mjs index d02e3d601..164680c69 100755 --- a/bin/package-locator.mjs +++ b/bin/package-locator.mjs @@ -1,59 +1,57 @@ #!/usr/bin/env node -import fs from 'fs' -import path from 'path' +import fs from 'fs'; +import path from 'path'; -const root = process.cwd() -const folder = process.argv[2] -const packagePath = path.join(root, folder) +const root = process.cwd(); +const folder = process.argv[2]; +const packagePath = path.join(root, folder); -const excludedDirs = ["node_modules", ".nais"] +const excludedDirs = ['node_modules', '.nais']; -const args = process.argv.slice(2) -const printHelp = args.indexOf('--help') > -1 || args.indexOf('-h') > -1 +const args = process.argv.slice(2); +const printHelp = args.indexOf('--help') > -1 || args.indexOf('-h') > -1; -const pkg = (name, path) => ({name, path}) -const stdoutFormat = array => JSON.stringify(array) +const pkg = (name, path) => ({ name, path }); +const stdoutFormat = (array) => JSON.stringify(array); if (printHelp) { - console.log("Usage: node package-locator.mjs ") - console.log() - console.log("Finds all package.json files recursively under given path, and writes a list of objects with package name and path to stdout.") - console.log(`Example output: ${stdoutFormat([pkg("pkg-a", "/app/pkg-a"), pkg("pkg-b", "/app/pkg-b")])}`) - console.log() - console.log("Excluded directories:", JSON.stringify(excludedDirs)) - process.exit(0) + console.log('Usage: node package-locator.mjs '); + console.log(); + console.log( + 'Finds all package.json files recursively under given path, and writes a list of objects with package name and path to stdout.', + ); + console.log(`Example output: ${stdoutFormat([pkg('pkg-a', '/app/pkg-a'), pkg('pkg-b', '/app/pkg-b')])}`); + console.log(); + console.log('Excluded directories:', JSON.stringify(excludedDirs)); + process.exit(0); } function parsePackageJson(filename) { - const jsonDataString = fs.readFileSync( - filename, - {encoding: 'utf-8', flag: 'r'}) - return JSON.parse(jsonDataString) + const jsonDataString = fs.readFileSync(filename, { encoding: 'utf-8', flag: 'r' }); + return JSON.parse(jsonDataString); } -const packages = [] +const packages = []; function searchPath(startPath, targetFilename) { - if (!fs.existsSync(startPath)) { - console.log("no dir:", startPath) - process.exit(1) + console.log('no dir:', startPath); + process.exit(1); } - const files = fs.readdirSync(startPath) - files.forEach(file => { - const filename = path.join(startPath, file) - const stat = fs.lstatSync(filename) + const files = fs.readdirSync(startPath); + files.forEach((file) => { + const filename = path.join(startPath, file); + const stat = fs.lstatSync(filename); if (stat.isDirectory() && !excludedDirs.includes(file)) { - searchPath(filename, targetFilename) //recurse + searchPath(filename, targetFilename); //recurse } else if (file === targetFilename) { - const packageJson = parsePackageJson(filename) - const currentDir = path.dirname(filename) - packages.push(pkg(packageJson.name, currentDir)) + const packageJson = parsePackageJson(filename); + const currentDir = path.dirname(filename); + packages.push(pkg(packageJson.name, currentDir)); } - - }) + }); } -searchPath(packagePath, 'package.json') -process.stdout.write(stdoutFormat(packages)) +searchPath(packagePath, 'package.json'); +process.stdout.write(stdoutFormat(packages)); diff --git a/bin/prepare-production-build.mjs b/bin/prepare-production-build.mjs index 38a23341f..c94d9df0d 100755 --- a/bin/prepare-production-build.mjs +++ b/bin/prepare-production-build.mjs @@ -1,32 +1,34 @@ #!/usr/bin/env node -import cp from 'child_process' -import path from 'path' +import cp from 'child_process'; +import path from 'path'; -const currentScriptPath = process.argv[1] -const scriptDir = path.dirname(currentScriptPath) -const packageLocatorScript = path.join(scriptDir, 'package-locator.mjs') -const deployContextScript = path.join(scriptDir, 'deploy-context.mjs') +const currentScriptPath = process.argv[1]; +const scriptDir = path.dirname(currentScriptPath); +const packageLocatorScript = path.join(scriptDir, 'package-locator.mjs'); +const deployContextScript = path.join(scriptDir, 'deploy-context.mjs'); -const args = process.argv.slice(2) -const dryRun = args.indexOf('--dry') > -1 -const printHelp = args.indexOf('--help') > -1 || args.indexOf('-h') > -1 +const args = process.argv.slice(2); +const dryRun = args.indexOf('--dry') > -1; +const printHelp = args.indexOf('--help') > -1 || args.indexOf('-h') > -1; if (printHelp) { - console.log("Usage: node prepare-production-build.mjs [--dry]") - console.log() - console.log("Calls script that finds all packages under folder named packages/, then runs deploy-context.mjs for each package.") - console.log("Use option --dry for running this script without applying changes.") - process.exit(0) + console.log('Usage: node prepare-production-build.mjs [--dry]'); + console.log(); + console.log( + 'Calls script that finds all packages under folder named packages/, then runs deploy-context.mjs for each package.', + ); + console.log('Use option --dry for running this script without applying changes.'); + process.exit(0); } -const deployContextArgs = ['--replace', '--absolute'] +const deployContextArgs = ['--replace', '--absolute']; if (dryRun) { - deployContextArgs.push('--dry') + deployContextArgs.push('--dry'); } -const packages = JSON.parse(cp.execFileSync(packageLocatorScript, ['packages/'])) -packages.forEach(pkg => { - console.log() - console.log(`Preparing ${pkg.name}...`) - cp.execFileSync(deployContextScript, [pkg.path, ...deployContextArgs], {stdio: 'inherit'}) -}) +const packages = JSON.parse(cp.execFileSync(packageLocatorScript, ['packages/'])); +packages.forEach((pkg) => { + console.log(); + console.log(`Preparing ${pkg.name}...`); + cp.execFileSync(deployContextScript, [pkg.path, ...deployContextArgs], { stdio: 'inherit' }); +}); diff --git a/docker/Dockerfile.bygger b/docker/Dockerfile.bygger index 7bffe96c4..573ca332c 100644 --- a/docker/Dockerfile.bygger +++ b/docker/Dockerfile.bygger @@ -1,4 +1,4 @@ -FROM node:18.16.1-alpine +FROM node:20.8.0-alpine ENV NODE_ENV production ARG git_sha diff --git a/docker/Dockerfile.fyllut-base b/docker/Dockerfile.fyllut-base index f9bbe1f0c..f322bcf91 100644 --- a/docker/Dockerfile.fyllut-base +++ b/docker/Dockerfile.fyllut-base @@ -1,4 +1,4 @@ -FROM node:18.16.1-alpine +FROM node:20.8.0-alpine ENV NODE_ENV production ARG git_sha diff --git a/package.json b/package.json index abee4542e..dfb0cd091 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "check-types": "yarn workspaces run check-types", "lint": "eslint . --ext .js,.jsx,.ts,.tsx,.mjs", "lint:staged": "lint-staged", - "prepare": "husky install" + "prepare": "husky install", + "prettier": "prettier --write ." }, "devDependencies": { "@testing-library/cypress": "^9.0.0", @@ -52,6 +53,7 @@ "cross-env": "^7.0.3", "cypress": "^13.3.0", "eslint": "^8.50.0", + "eslint-config-prettier": "^9.0.0", "eslint-plugin-cypress": "^2.15.1", "eslint-plugin-import": "^2.28.1", "eslint-plugin-react": "^7.33.2", @@ -59,8 +61,8 @@ "eslint-plugin-testing-library": "^6.0.2", "eslint-plugin-vitest": "^0.3.1", "eslint-plugin-vitest-globals": "^1.4.0", - "jsdom": "^22.1.0", "husky": "^8.0.3", + "jsdom": "^22.1.0", "lint-staged": "^14.0.1", "prettier": "^3.0.3", "prettier-plugin-organize-imports": "^3.2.3", @@ -73,7 +75,7 @@ "vitest-fetch-mock": "^0.2.2" }, "engines": { - "node": ">=18.16.0" + "node": ">=20.0.0" }, "lint-staged": { "*.{js,jsx,ts,tsx,mjs}": [ diff --git a/packages/bygger-backend/__mocks__/@octokit/auth-app.js b/packages/bygger-backend/__mocks__/@octokit/auth-app.js index d7b6bba31..c34d29d7d 100644 --- a/packages/bygger-backend/__mocks__/@octokit/auth-app.js +++ b/packages/bygger-backend/__mocks__/@octokit/auth-app.js @@ -1 +1 @@ -export const createAppAuth = vi.fn().mockReturnValue(() => ({ auth: () => ({ token: "" }) })); +export const createAppAuth = vi.fn().mockReturnValue(() => ({ auth: () => ({ token: '' }) })); diff --git a/packages/bygger-backend/__mocks__/GitHubRepo.js b/packages/bygger-backend/__mocks__/GitHubRepo.js index 012b57415..6d9309ce3 100644 --- a/packages/bygger-backend/__mocks__/GitHubRepo.js +++ b/packages/bygger-backend/__mocks__/GitHubRepo.js @@ -1,12 +1,12 @@ -export const mockRepoGetRef = vi.fn().mockReturnValue({ data: { object: { sha: "sha" } } }); +export const mockRepoGetRef = vi.fn().mockReturnValue({ data: { object: { sha: 'sha' } } }); export const mockRepoCreateRef = vi.fn(); export const mockRepoDeleteRef = vi.fn(); export const mockRepoGetFileIfItExists = vi .fn() - .mockReturnValue({ data: { sha: "existing-file-sha", content: "content" } }); + .mockReturnValue({ data: { sha: 'existing-file-sha', content: 'content' } }); export const mockRepoCreateOrUpdateFileContents = vi .fn() - .mockReturnValue({ data: { commit: { sha: "new-commit-sha" } } }); + .mockReturnValue({ data: { commit: { sha: 'new-commit-sha' } } }); export const mockRepoCreatePullRequest = vi.fn().mockReturnValue({ data: { number: 14 } }); export const mockRepoMergePullRequest = vi.fn(); export const mockRepoHasBranchChanged = vi diff --git a/packages/bygger-backend/src/Backend.test.ts b/packages/bygger-backend/src/Backend.test.ts index dda96a05f..929e6ce0b 100644 --- a/packages/bygger-backend/src/Backend.test.ts +++ b/packages/bygger-backend/src/Backend.test.ts @@ -7,19 +7,19 @@ import { mockRepoGetRef, mockRepoHasBranchChanged, mockRepoMergePullRequest, -} from "../__mocks__/GitHubRepo"; -import { configForTest, createBackendForTest } from "../testTools/backend/testUtils.js"; -import { GitHubRepo } from "./GitHubRepo.js"; -import { stringTobase64 } from "./fetchUtils"; -import { pushEventWithCommitMessage } from "./testdata/default-github-push-event"; - -vi.mock("uuid", () => { - return { v4: vi.fn().mockReturnValue("1234") }; +} from '../__mocks__/GitHubRepo'; +import { configForTest, createBackendForTest } from '../testTools/backend/testUtils.js'; +import { GitHubRepo } from './GitHubRepo.js'; +import { stringTobase64 } from './fetchUtils'; +import { pushEventWithCommitMessage } from './testdata/default-github-push-event'; + +vi.mock('uuid', () => { + return { v4: vi.fn().mockReturnValue('1234') }; }); -vi.mock("./GitHubRepo.js"); +vi.mock('./GitHubRepo.js'); -describe("Backend", () => { - const formPath = "skjema"; +describe('Backend', () => { + const formPath = 'skjema'; beforeEach(() => { // @ts-ignore @@ -56,100 +56,100 @@ describe("Backend", () => { mockRepoMergePullRequest.mockClear(); }); - describe("publishForm", () => { - const expectedBranchName = "publish-skjema--1234"; + describe('publishForm', () => { + const expectedBranchName = 'publish-skjema--1234'; - describe("When file content is different from the corresponding file in the repo", () => { + describe('When file content is different from the corresponding file in the repo', () => { beforeEach(async () => { - await backend.publishForm({ title: "Form" }, { en: {} }, formPath); + await backend.publishForm({ title: 'Form' }, { en: {} }, formPath); }); - it("creates instance of GitHubRepo.js", () => { + it('creates instance of GitHubRepo.js', () => { expect(GitHubRepo).toHaveBeenCalledTimes(1); expect(GitHubRepo).toHaveBeenCalledWith( - "publish-repo-owner", - "publish-repo", + 'publish-repo-owner', + 'publish-repo', expect.objectContaining(configForTest.githubApp), ); }); - it("creates a new branch in the target repo", () => { + it('creates a new branch in the target repo', () => { expect(mockRepoCreateRef).toHaveBeenCalledTimes(1); - expect(mockRepoCreateRef).toHaveBeenCalledWith(expectedBranchName, "sha"); + expect(mockRepoCreateRef).toHaveBeenCalledWith(expectedBranchName, 'sha'); }); - it("pushes form and translations on a separate branch", () => { + it('pushes form and translations on a separate branch', () => { expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledTimes(2); expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledWith( expectedBranchName, `forms/${formPath}.json`, 'skjema "Form", monorepo ref: publish-repo-git-sha', - "eyJ0aXRsZSI6IkZvcm0ifQ==", - "existing-file-sha", + 'eyJ0aXRsZSI6IkZvcm0ifQ==', + 'existing-file-sha', ); expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledWith( expectedBranchName, `translations/${formPath}.json`, 'oversettelse "Form", monorepo ref: publish-repo-git-sha', - "eyJlbiI6e319", - "existing-file-sha", + 'eyJlbiI6e319', + 'existing-file-sha', ); }); - it("deletes the branch", () => { + it('deletes the branch', () => { expect(mockRepoDeleteRef).toHaveBeenCalledTimes(1); expect(mockRepoDeleteRef).toHaveBeenCalledWith(expectedBranchName); }); }); - describe("When file content is the same as the corresponding file in the repo", () => { + describe('When file content is the same as the corresponding file in the repo', () => { beforeEach(async () => { - const fileContent = { title: "Form" }; + const fileContent = { title: 'Form' }; mockRepoGetFileIfItExists.mockReturnValueOnce({ - data: { content: stringTobase64(JSON.stringify(fileContent)), sha: "sha" }, + data: { content: stringTobase64(JSON.stringify(fileContent)), sha: 'sha' }, }); mockRepoGetFileIfItExists.mockReturnValueOnce({ - data: { content: stringTobase64(JSON.stringify({})), sha: "sha" }, + data: { content: stringTobase64(JSON.stringify({})), sha: 'sha' }, }); await backend.publishForm(fileContent, {}, formPath); }); - it("does not push the file", () => { + it('does not push the file', () => { expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledTimes(0); }); - it("deletes the branch", () => { + it('deletes the branch', () => { expect(mockRepoDeleteRef).toHaveBeenCalledTimes(1); expect(mockRepoDeleteRef).toHaveBeenCalledWith(expectedBranchName); }); }); - describe("when changes are pushed", () => { + describe('when changes are pushed', () => { beforeEach(async () => { - mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: "original-sha-for-base-branch" } } }); - mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: "different-sha-for-new-branch" } } }); - mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: "different-sha-after-pushing-files" } } }); - mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: "resulting-sha-after-merge" } } }); - await backend.publishForm({ title: "Form" }, { en: {} }, formPath); + mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: 'original-sha-for-base-branch' } } }); + mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: 'different-sha-for-new-branch' } } }); + mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: 'different-sha-after-pushing-files' } } }); + mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: 'resulting-sha-after-merge' } } }); + await backend.publishForm({ title: 'Form' }, { en: {} }, formPath); }); - it("updates monorepo ref", () => { + it('updates monorepo ref', () => { expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledTimes(3); - expect(mockRepoCreateOrUpdateFileContents.mock.calls[0][1]).toEqual("forms/skjema.json"); - expect(mockRepoCreateOrUpdateFileContents.mock.calls[1][1]).toEqual("translations/skjema.json"); - expect(mockRepoCreateOrUpdateFileContents.mock.calls[2][1]).toEqual("MONOREPO"); + expect(mockRepoCreateOrUpdateFileContents.mock.calls[0][1]).toBe('forms/skjema.json'); + expect(mockRepoCreateOrUpdateFileContents.mock.calls[1][1]).toBe('translations/skjema.json'); + expect(mockRepoCreateOrUpdateFileContents.mock.calls[2][1]).toBe('MONOREPO'); }); - it("creates a pull request", () => { + it('creates a pull request', () => { expect(mockRepoCreatePullRequest).toHaveBeenCalledTimes(1); expect(mockRepoCreatePullRequest).toHaveBeenCalledWith( - "Automatic publishing job", + 'Automatic publishing job', expectedBranchName, - "publish-repo-main-branch", + 'publish-repo-main-branch', ); }); - it("merges the the pull request", async () => { + it('merges the the pull request', async () => { expect(mockRepoMergePullRequest).toHaveBeenCalledTimes(1); expect(mockRepoMergePullRequest).toHaveBeenCalledWith( 14, @@ -158,75 +158,75 @@ describe("Backend", () => { }); }); - describe("when no changes are pushed", () => { + describe('when no changes are pushed', () => { beforeEach(async () => { - await backend.publishForm({ title: "Form" }, { en: {} }, formPath); + await backend.publishForm({ title: 'Form' }, { en: {} }, formPath); }); - it("does not update monorepo ref", () => { + it('does not update monorepo ref', () => { expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledTimes(2); - expect(mockRepoCreateOrUpdateFileContents.mock.calls[0][1]).toEqual("forms/skjema.json"); - expect(mockRepoCreateOrUpdateFileContents.mock.calls[1][1]).toEqual("translations/skjema.json"); + expect(mockRepoCreateOrUpdateFileContents.mock.calls[0][1]).toBe('forms/skjema.json'); + expect(mockRepoCreateOrUpdateFileContents.mock.calls[1][1]).toBe('translations/skjema.json'); }); - it("does not merge the pull request", () => { + it('does not merge the pull request', () => { expect(mockRepoMergePullRequest).toHaveBeenCalledTimes(0); }); - it("deletes the branch", () => { + it('deletes the branch', () => { expect(mockRepoDeleteRef).toHaveBeenCalledTimes(1); expect(mockRepoDeleteRef).toHaveBeenCalledWith(expectedBranchName); }); }); }); - describe("publishResource", () => { - const expectedBranchName = "publish-settings--1234"; + describe('publishResource', () => { + const expectedBranchName = 'publish-settings--1234'; beforeEach(() => { - mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: "original-sha-for-base-branch" } } }); - mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: "different-sha-for-new-branch" } } }); - mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: "different-sha-after-pushing-file" } } }); - mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: "resulting-sha-after-merge" } } }); + mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: 'original-sha-for-base-branch' } } }); + mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: 'different-sha-for-new-branch' } } }); + mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: 'different-sha-after-pushing-file' } } }); + mockRepoGetRef.mockReturnValueOnce({ data: { object: { sha: 'resulting-sha-after-merge' } } }); }); - describe("When file already exists", () => { + describe('When file already exists', () => { beforeEach(async () => { - await backend.publishResource("settings", { toggle: "on" }); + await backend.publishResource('settings', { toggle: 'on' }); }); - it("creates instance of GitHubRepo.js", () => { + it('creates instance of GitHubRepo.js', () => { expect(GitHubRepo).toHaveBeenCalledTimes(1); expect(GitHubRepo).toHaveBeenCalledWith( - "publish-repo-owner", - "publish-repo", + 'publish-repo-owner', + 'publish-repo', expect.objectContaining(configForTest.githubApp), ); }); - it("creates a new branch in the target repo", () => { + it('creates a new branch in the target repo', () => { expect(mockRepoCreateRef).toHaveBeenCalledTimes(1); - expect(mockRepoCreateRef).toHaveBeenCalledWith(expectedBranchName, "original-sha-for-base-branch"); + expect(mockRepoCreateRef).toHaveBeenCalledWith(expectedBranchName, 'original-sha-for-base-branch'); }); - it("sends the sha of the original file to createOrUpdateFile", () => { + it('sends the sha of the original file to createOrUpdateFile', () => { expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledTimes(2); expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledWith( expectedBranchName, - "resources/settings.json", + 'resources/settings.json', 'ressurs "settings", monorepo ref: publish-repo-git-sha', - "eyJ0b2dnbGUiOiJvbiJ9", - "existing-file-sha", + 'eyJ0b2dnbGUiOiJvbiJ9', + 'existing-file-sha', ); }); - it("updates monorepo ref", () => { + it('updates monorepo ref', () => { expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledTimes(2); - expect(mockRepoCreateOrUpdateFileContents.mock.calls[0][1]).toEqual("resources/settings.json"); - expect(mockRepoCreateOrUpdateFileContents.mock.calls[1][1]).toEqual("MONOREPO"); + expect(mockRepoCreateOrUpdateFileContents.mock.calls[0][1]).toBe('resources/settings.json'); + expect(mockRepoCreateOrUpdateFileContents.mock.calls[1][1]).toBe('MONOREPO'); }); - it("deletes the branch", () => { + it('deletes the branch', () => { expect(mockRepoDeleteRef).toHaveBeenCalledTimes(1); expect(mockRepoDeleteRef).toHaveBeenCalledWith(expectedBranchName); }); @@ -235,115 +235,115 @@ describe("Backend", () => { describe("When the file doesn't exist in the repo", () => { beforeEach(async () => { mockRepoGetFileIfItExists.mockReturnValue(undefined); - await backend.publishResource("settings", { toggle: "on" }); + await backend.publishResource('settings', { toggle: 'on' }); }); - it("calls createOrUpdateFile without a sha", () => { + it('calls createOrUpdateFile without a sha', () => { expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledTimes(2); expect(mockRepoCreateOrUpdateFileContents).toHaveBeenCalledWith( expectedBranchName, - "resources/settings.json", + 'resources/settings.json', 'ressurs "settings", monorepo ref: publish-repo-git-sha', - "eyJ0b2dnbGUiOiJvbiJ9", + 'eyJ0b2dnbGUiOiJvbiJ9', undefined, ); }); }); }); - describe("interpretGithubPushEvent", () => { - describe("bulk publication", () => { - const commitMessage = "[bulk-publisering] 23 skjemaer publisert, monorepo ref: 1234567890"; + describe('interpretGithubPushEvent', () => { + describe('bulk publication', () => { + const commitMessage = '[bulk-publisering] 23 skjemaer publisert, monorepo ref: 1234567890'; - it("success message includes number of forms published", () => { + it('success message includes number of forms published', () => { const githubEvent = pushEventWithCommitMessage(commitMessage); - const result = backend.interpretGithubPushEvent(githubEvent, "success"); + const result = backend.interpretGithubPushEvent(githubEvent, 'success'); expect(result).toEqual({ - type: "success", - title: "Bulk-publisering fullført", - message: "23 skjemaer ble bulk-publisert", + type: 'success', + title: 'Bulk-publisering fullført', + message: '23 skjemaer ble bulk-publisert', }); }); - it("failure message includes number of forms published", () => { + it('failure message includes number of forms published', () => { const githubEvent = pushEventWithCommitMessage(commitMessage); - const result = backend.interpretGithubPushEvent(githubEvent, "failure"); + const result = backend.interpretGithubPushEvent(githubEvent, 'failure'); expect(result).toEqual({ - type: "failure", - title: "Bulk-publisering feilet", - message: "23 skjemaer feilet", + type: 'failure', + title: 'Bulk-publisering feilet', + message: '23 skjemaer feilet', }); }); }); - describe("publication", () => { + describe('publication', () => { const commitMessage = '[publisering] skjema "Testskjema", monorepo ref: 1234567890'; - it("success message includes form title", () => { + it('success message includes form title', () => { const githubEvent = pushEventWithCommitMessage(commitMessage); - const result = backend.interpretGithubPushEvent(githubEvent, "success"); + const result = backend.interpretGithubPushEvent(githubEvent, 'success'); expect(result).toEqual({ - type: "success", - title: "Publisering fullført", - message: "Skjema Testskjema er nå publisert", + type: 'success', + title: 'Publisering fullført', + message: 'Skjema Testskjema er nå publisert', }); }); - it("failure message includes form title", () => { + it('failure message includes form title', () => { const githubEvent = pushEventWithCommitMessage(commitMessage); - const result = backend.interpretGithubPushEvent(githubEvent, "failure"); + const result = backend.interpretGithubPushEvent(githubEvent, 'failure'); expect(result).toEqual({ - type: "failure", - title: "Publisering feilet", - message: "Feilet for skjema Testskjema", + type: 'failure', + title: 'Publisering feilet', + message: 'Feilet for skjema Testskjema', }); }); }); - describe("unpublishing", () => { - const commitMessage = "[avpublisering] skjema nav123456, monorepo ref: 1234567890"; + describe('unpublishing', () => { + const commitMessage = '[avpublisering] skjema nav123456, monorepo ref: 1234567890'; - it("success message includes form title", () => { + it('success message includes form title', () => { const githubEvent = pushEventWithCommitMessage(commitMessage); - const result = backend.interpretGithubPushEvent(githubEvent, "success"); + const result = backend.interpretGithubPushEvent(githubEvent, 'success'); expect(result).toEqual({ - type: "success", - title: "Avpublisering fullført", - message: "Skjema nav123456 er nå avpublisert", + type: 'success', + title: 'Avpublisering fullført', + message: 'Skjema nav123456 er nå avpublisert', }); }); - it("failure message includes form title", () => { + it('failure message includes form title', () => { const githubEvent = pushEventWithCommitMessage(commitMessage); - const result = backend.interpretGithubPushEvent(githubEvent, "failure"); + const result = backend.interpretGithubPushEvent(githubEvent, 'failure'); expect(result).toEqual({ - type: "failure", - title: "Avpublisering feilet", - message: "Feilet for skjema nav123456", + type: 'failure', + title: 'Avpublisering feilet', + message: 'Feilet for skjema nav123456', }); }); }); - describe("random commit to repo skjemautfylling-formio", () => { - const commitMessage = "Endret tekstene"; + describe('random commit to repo skjemautfylling-formio', () => { + const commitMessage = 'Endret tekstene'; - it("success message includes form title", () => { + it('success message includes form title', () => { const githubEvent = pushEventWithCommitMessage(commitMessage); - const result = backend.interpretGithubPushEvent(githubEvent, "success"); + const result = backend.interpretGithubPushEvent(githubEvent, 'success'); expect(result).toEqual({ - type: "success", - title: "Ny versjon av FyllUt", - message: "Endret tekstene", + type: 'success', + title: 'Ny versjon av FyllUt', + message: 'Endret tekstene', }); }); - it("failure message includes form title", () => { + it('failure message includes form title', () => { const githubEvent = pushEventWithCommitMessage(commitMessage); - const result = backend.interpretGithubPushEvent(githubEvent, "failure"); + const result = backend.interpretGithubPushEvent(githubEvent, 'failure'); expect(result).toEqual({ - type: "failure", - title: "Deploy av FyllUt feilet", - message: "Endret tekstene", + type: 'failure', + title: 'Deploy av FyllUt feilet', + message: 'Endret tekstene', }); }); }); diff --git a/packages/bygger-backend/src/Backend.ts b/packages/bygger-backend/src/Backend.ts index 635ec4156..35bab5231 100644 --- a/packages/bygger-backend/src/Backend.ts +++ b/packages/bygger-backend/src/Backend.ts @@ -1,10 +1,10 @@ -import { I18nTranslations, NavFormType, ResourceContent } from "@navikt/skjemadigitalisering-shared-domain"; -import { PushEvent } from "@octokit/webhooks-types"; -import { v4 as uuidv4 } from "uuid"; -import { GitHubRepo } from "./GitHubRepo.js"; -import { ConfigType } from "./config/types"; -import { base64ToString, fetchWithErrorHandling } from "./fetchUtils"; -import { logger } from "./logging/logger"; +import { I18nTranslations, NavFormType, ResourceContent } from '@navikt/skjemadigitalisering-shared-domain'; +import { PushEvent } from '@octokit/webhooks-types'; +import { v4 as uuidv4 } from 'uuid'; +import { GitHubRepo } from './GitHubRepo.js'; +import { ConfigType } from './config/types'; +import { base64ToString, fetchWithErrorHandling } from './fetchUtils'; +import { logger } from './logging/logger'; import { createFileForPushingToRepo, deleteFilesAndUpdateMonorepoRefCallback, @@ -12,8 +12,8 @@ import { getTranslationFilePath, performChangesOnSeparateBranch, pushFilesAndUpdateMonorepoRefCallback, -} from "./repoUtils.js"; -import { FormioService } from "./services/formioService"; +} from './repoUtils.js'; +import { FormioService } from './services/formioService'; const BULK_PUBLISH_REGEXP = /^\[bulk-publisering\] (\d+) skjemaer publisert, monorepo ref: (.*)$/; const PUBLISH_REGEXP = /^\[publisering\] skjema "(.*)", monorepo ref: (.*)$/; @@ -39,7 +39,7 @@ export class Backend { async publishForm(formContent: NavFormType, translationsContent: I18nTranslations | undefined, formPath: string) { const skjemautfyllingRepo = await this.createGitHubRepo(); - const formFile = createFileForPushingToRepo(formContent.title, getFormFilePath(formPath), "skjema", formContent); + const formFile = createFileForPushingToRepo(formContent.title, getFormFilePath(formPath), 'skjema', formContent); const files = [formFile]; const branchName = `publish-${formPath}--${uuidv4()}`; @@ -47,7 +47,7 @@ export class Backend { const translationsFile = createFileForPushingToRepo( formContent.title, getTranslationFilePath(formPath), - "oversettelse", + 'oversettelse', translationsContent, ); files.push(translationsFile); @@ -102,7 +102,7 @@ export class Backend { const resourceFile = createFileForPushingToRepo( resourceName, `resources/${resourceName}.json`, - "ressurs", + 'ressurs', resourceContent, ); @@ -136,7 +136,7 @@ export class Backend { const skjemautfyllingRepo = await this.createGitHubRepo(); const branchName = `bulkpublish--${uuidv4()}`; const formFiles = forms.map((formContent: NavFormType) => - createFileForPushingToRepo(formContent.title, `forms/${formContent.path}.json`, "skjema", formContent), + createFileForPushingToRepo(formContent.title, `forms/${formContent.path}.json`, 'skjema', formContent), ); logger.info( @@ -158,21 +158,21 @@ export class Backend { } interpretGithubPushEvent(pushEvent: PushEvent, type: string) { - const success = type === "success"; + const success = type === 'success'; const thisCommit = pushEvent.head_commit; - const commitMessage = thisCommit?.message || ""; + const commitMessage = thisCommit?.message || ''; - const titleRegexp = new RegExp(PUBLISH_REGEXP, "g"); + const titleRegexp = new RegExp(PUBLISH_REGEXP, 'g'); const publishFormTitleMatch = titleRegexp.exec(commitMessage); - const unpublishRegexp = new RegExp(UNPUBLISH_REGEXP, "g"); + const unpublishRegexp = new RegExp(UNPUBLISH_REGEXP, 'g'); const unpublishFormPathMatch = unpublishRegexp.exec(commitMessage); - const amountRegexp = new RegExp(BULK_PUBLISH_REGEXP, "g"); + const amountRegexp = new RegExp(BULK_PUBLISH_REGEXP, 'g'); const bulkPublishCountMatch = amountRegexp.exec(commitMessage); if (publishFormTitleMatch) { return { type, - title: success ? "Publisering fullført" : "Publisering feilet", + title: success ? 'Publisering fullført' : 'Publisering feilet', message: success ? `Skjema ${publishFormTitleMatch[1]} er nå publisert` : `Feilet for skjema ${publishFormTitleMatch[1]}`, @@ -181,7 +181,7 @@ export class Backend { if (unpublishFormPathMatch) { return { type, - title: success ? "Avpublisering fullført" : "Avpublisering feilet", + title: success ? 'Avpublisering fullført' : 'Avpublisering feilet', message: success ? `Skjema ${unpublishFormPathMatch[1]} er nå avpublisert` : `Feilet for skjema ${unpublishFormPathMatch[1]}`, @@ -190,7 +190,7 @@ export class Backend { if (bulkPublishCountMatch) { return { type, - title: success ? "Bulk-publisering fullført" : "Bulk-publisering feilet", + title: success ? 'Bulk-publisering fullført' : 'Bulk-publisering feilet', message: success ? `${bulkPublishCountMatch[1]} skjemaer ble bulk-publisert` : `${bulkPublishCountMatch[1]} skjemaer feilet`, @@ -198,20 +198,20 @@ export class Backend { } return { type, - title: success ? "Ny versjon av FyllUt" : "Deploy av FyllUt feilet", + title: success ? 'Ny versjon av FyllUt' : 'Deploy av FyllUt feilet', message: commitMessage, }; } async fetchEnhetsliste() { return fetchWithErrorHandling(`${this.config.fyllut.baseUrl}/api/enhetsliste`, { - method: "GET", + method: 'GET', }).then((response) => response.data); } async fetchTemakoder() { return fetchWithErrorHandling(`${this.config.fyllut.baseUrl}/api/common-codes/archive-subjects`, { - method: "GET", + method: 'GET', }).then((response) => response.data); } @@ -219,11 +219,11 @@ export class Backend { const skjemautfyllingRepo = await this.createGitHubRepo(); const filePath = getFormFilePath(formPath); logger.debug(`Fetch published form ${filePath} from ${this.config.publishRepo.base}`); - const response = await skjemautfyllingRepo.getFileIfItExists(this.config.publishRepo.base || "master", filePath); - if (response && "content" in response.data) { + const response = await skjemautfyllingRepo.getFileIfItExists(this.config.publishRepo.base || 'master', filePath); + if (response && 'content' in response.data) { const logData = { ...response?.data }; logData.content = `${logData.content.substring(0, 20)}...`; - logger.debug("Retrieved published form", logData); + logger.debug('Retrieved published form', logData); const content = base64ToString(response.data.content); return JSON.parse(content); diff --git a/packages/bygger-backend/src/GitHubRepo.js b/packages/bygger-backend/src/GitHubRepo.js index eb14bf84b..b73791710 100644 --- a/packages/bygger-backend/src/GitHubRepo.js +++ b/packages/bygger-backend/src/GitHubRepo.js @@ -1,12 +1,12 @@ -import { createAppAuth } from "@octokit/auth-app"; -import { Octokit } from "@octokit/rest"; -import { logger } from "./logging/logger"; +import { createAppAuth } from '@octokit/auth-app'; +import { Octokit } from '@octokit/rest'; +import { logger } from './logging/logger'; // Not exhaustive export const gitTreeMode = { - BLOB: "100644", - EXECUTABLE: "100755", - DIRECTORY: "040000", + BLOB: '100644', + EXECUTABLE: '100755', + DIRECTORY: '040000', }; export class GitHubRepo { @@ -31,22 +31,22 @@ export class GitHubRepo { clientSecret: this.credentials.clientSecret, }); this.authentication = await auth({ - type: "installation", + type: 'installation', installationId: this.credentials.installationId, }); - logger.debug("Authenticate on Github as app installation"); + logger.debug('Authenticate on Github as app installation'); } const auth = this.authentication?.token ?? this.credentials.token; if (auth === undefined) { logger.error( - "Github authentication token is missing. Make sure that either GITHUB_ACCESS_TOKEN or github app credentials are present as environment variables", + 'Github authentication token is missing. Make sure that either GITHUB_ACCESS_TOKEN or github app credentials are present as environment variables', ); } this.octokit = new Octokit({ auth, - userAgent: "navikt/skjemabygging", - baseUrl: "https://api.github.com", + userAgent: 'navikt/skjemabygging', + baseUrl: 'https://api.github.com', log: { debug: () => {}, info: () => {}, @@ -127,7 +127,7 @@ export class GitHubRepo { repo: this.repo, pull_number, commit_title, - commit_message: "", + commit_message: '', }); } diff --git a/packages/bygger-backend/src/GitHubRepo.test.js b/packages/bygger-backend/src/GitHubRepo.test.js index aa02ea121..85a6bedf8 100644 --- a/packages/bygger-backend/src/GitHubRepo.test.js +++ b/packages/bygger-backend/src/GitHubRepo.test.js @@ -11,16 +11,16 @@ import { mockMergePullRequest, mockUpdateRef, Octokit, -} from "@octokit/rest"; -import { configForTest } from "../testTools/backend/testUtils"; -import { GitHubRepo } from "./GitHubRepo.js"; +} from '@octokit/rest'; +import { configForTest } from '../testTools/backend/testUtils'; +import { GitHubRepo } from './GitHubRepo.js'; -vi.mock("@octokit/rest"); +vi.mock('@octokit/rest'); -describe("GitHubRepo", () => { +describe('GitHubRepo', () => { let repo; - const owner = "myOrganization"; - const repoName = "myRepo"; + const owner = 'myOrganization'; + const repoName = 'myRepo'; beforeEach(() => { repo = new GitHubRepo(owner, repoName, configForTest.githubApp); @@ -42,116 +42,116 @@ describe("GitHubRepo", () => { mockMergePullRequest.mockClear(); }); - it("creates instance of octokit and authenticates with provided pat", () => { + it('creates instance of octokit and authenticates with provided pat', () => { expect(Octokit).toHaveBeenCalledTimes(1); expect(Octokit).toHaveBeenLastCalledWith(expect.objectContaining({ auth: undefined })); }); - describe("getRef", () => { - it("calls octokit.rest.git.getRef with ref: heads/main", () => { - repo.getRef("main"); + describe('getRef', () => { + it('calls octokit.rest.git.getRef with ref: heads/main', () => { + repo.getRef('main'); expect(mockGetRef).toHaveBeenCalledTimes(1); - expect(mockGetRef).toHaveBeenCalledWith({ owner, repo: repoName, ref: "heads/main" }); + expect(mockGetRef).toHaveBeenCalledWith({ owner, repo: repoName, ref: 'heads/main' }); }); }); - describe("hasBranchChanged", () => { - it("returns false, if ref sha is the same as the branch sha", async () => { - const ref = { data: { object: { sha: "branch-sha" } } }; - mockGetRef.mockReturnValueOnce({ data: { object: { sha: "branch-sha" } } }); - expect(await repo.hasBranchChanged(ref, "branch")).toBe(false); + describe('hasBranchChanged', () => { + it('returns false, if ref sha is the same as the branch sha', async () => { + const ref = { data: { object: { sha: 'branch-sha' } } }; + mockGetRef.mockReturnValueOnce({ data: { object: { sha: 'branch-sha' } } }); + expect(await repo.hasBranchChanged(ref, 'branch')).toBe(false); }); - it("returns true, if ref sha is different from the branch sha", async () => { - const ref = { data: { object: { sha: "ref-sha" } } }; - mockGetRef.mockReturnValueOnce({ data: { object: { sha: "branch-sha" } } }); - expect(await repo.hasBranchChanged(ref, "branch")).toBe(true); + it('returns true, if ref sha is different from the branch sha', async () => { + const ref = { data: { object: { sha: 'ref-sha' } } }; + mockGetRef.mockReturnValueOnce({ data: { object: { sha: 'branch-sha' } } }); + expect(await repo.hasBranchChanged(ref, 'branch')).toBe(true); }); }); - describe("createRef", () => { - it("calls octokit.rest.git.createRef with ref: refs/heads/new-branch", () => { - repo.createRef("new-branch"); + describe('createRef', () => { + it('calls octokit.rest.git.createRef with ref: refs/heads/new-branch', () => { + repo.createRef('new-branch'); expect(mockCreateRef).toHaveBeenCalledTimes(1); - expect(mockCreateRef).toHaveBeenCalledWith({ owner, repo: repoName, ref: "refs/heads/new-branch" }); + expect(mockCreateRef).toHaveBeenCalledWith({ owner, repo: repoName, ref: 'refs/heads/new-branch' }); }); }); - describe("deleteRef", () => { - it("calls octokit.rest.git.deleteRef with ref: heads/new-branch", () => { - repo.deleteRef("new-branch"); + describe('deleteRef', () => { + it('calls octokit.rest.git.deleteRef with ref: heads/new-branch', () => { + repo.deleteRef('new-branch'); expect(mockDeleteRef).toHaveBeenCalledTimes(1); - expect(mockDeleteRef).toHaveBeenCalledWith({ owner, repo: repoName, ref: "heads/new-branch" }); + expect(mockDeleteRef).toHaveBeenCalledWith({ owner, repo: repoName, ref: 'heads/new-branch' }); }); }); - describe("getFileIfItExists", () => { - it("calls octokit.rest.repos.getContent", () => { - repo.getFileIfItExists("main", "files/myFile.json"); + describe('getFileIfItExists', () => { + it('calls octokit.rest.repos.getContent', () => { + repo.getFileIfItExists('main', 'files/myFile.json'); expect(mockGetContent).toHaveBeenCalledTimes(1); - expect(mockGetContent).toHaveBeenCalledWith({ owner, repo: repoName, ref: "main", path: "files/myFile.json" }); + expect(mockGetContent).toHaveBeenCalledWith({ owner, repo: repoName, ref: 'main', path: 'files/myFile.json' }); }); }); - describe("createOrUpdateFileContents", () => { - it("calls rest.repos.createOrUpdateFileContents with the provided sha", () => { + describe('createOrUpdateFileContents', () => { + it('calls rest.repos.createOrUpdateFileContents with the provided sha', () => { repo.createOrUpdateFileContents( - "new-branch", - "files/existingFile.json", - "Update existingFile.json", - "base64-string", - "sha for existingFile.json", + 'new-branch', + 'files/existingFile.json', + 'Update existingFile.json', + 'base64-string', + 'sha for existingFile.json', ); expect(mockCreateOrUpdateFileContents).toHaveBeenCalledTimes(1); expect(mockCreateOrUpdateFileContents).toHaveBeenCalledWith({ owner, repo: repoName, - branch: "new-branch", - path: "files/existingFile.json", - message: "Update existingFile.json", - content: "base64-string", - sha: "sha for existingFile.json", + branch: 'new-branch', + path: 'files/existingFile.json', + message: 'Update existingFile.json', + content: 'base64-string', + sha: 'sha for existingFile.json', }); }); - it("omits sha from parameters when not provided", () => { - repo.createOrUpdateFileContents("new-branch", "files/newFile.json", "Create newFile.json", "base64-string"); + it('omits sha from parameters when not provided', () => { + repo.createOrUpdateFileContents('new-branch', 'files/newFile.json', 'Create newFile.json', 'base64-string'); expect(mockCreateOrUpdateFileContents).toHaveBeenCalledTimes(1); expect(mockCreateOrUpdateFileContents).toHaveBeenCalledWith({ owner, repo: repoName, - branch: "new-branch", - path: "files/newFile.json", - message: "Create newFile.json", - content: "base64-string", + branch: 'new-branch', + path: 'files/newFile.json', + message: 'Create newFile.json', + content: 'base64-string', }); }); }); - describe("createPullRequest", () => { - it("calls octokit.rest.pulls.create", () => { - repo.createPullRequest("New PR", "new-branch", "main"); + describe('createPullRequest', () => { + it('calls octokit.rest.pulls.create', () => { + repo.createPullRequest('New PR', 'new-branch', 'main'); expect(mockCreatePullRequest).toHaveBeenCalledTimes(1); expect(mockCreatePullRequest).toHaveBeenCalledWith({ owner, repo: repoName, - title: "New PR", - head: "new-branch", - base: "main", + title: 'New PR', + head: 'new-branch', + base: 'main', }); }); }); - describe("mergePullRequest", () => { - it("calls octokit.rest.pulls.merge", () => { - repo.mergePullRequest(14, "message"); + describe('mergePullRequest', () => { + it('calls octokit.rest.pulls.merge', () => { + repo.mergePullRequest(14, 'message'); expect(mockMergePullRequest).toHaveBeenCalledTimes(1); expect(mockMergePullRequest).toHaveBeenCalledWith({ owner, repo: repoName, pull_number: 14, - commit_title: "message", - commit_message: "", + commit_title: 'message', + commit_message: '', }); }); }); diff --git a/packages/bygger-backend/src/config/development.ts b/packages/bygger-backend/src/config/development.ts index aa85ea6d4..76af93934 100644 --- a/packages/bygger-backend/src/config/development.ts +++ b/packages/bygger-backend/src/config/development.ts @@ -6,39 +6,39 @@ import { PublishRepoConfig, PusherConfig, SkjemabyggingProxyConfig, -} from "./types"; +} from './types'; export const devAzure: Partial = { - openidTokenEndpoint: "https://login.microsoftonline.com/966ac572-f5b7-4bbe-aa88-c76419c0f851/oauth2/v2.0/token", - openidConfigJwksUri: "https://login.microsoftonline.com/966ac572-f5b7-4bbe-aa88-c76419c0f851/discovery/v2.0/keys", - clientId: "599b3553-24b0-416f-9a91-3866d1197e90", + openidTokenEndpoint: 'https://login.microsoftonline.com/966ac572-f5b7-4bbe-aa88-c76419c0f851/oauth2/v2.0/token', + openidConfigJwksUri: 'https://login.microsoftonline.com/966ac572-f5b7-4bbe-aa88-c76419c0f851/discovery/v2.0/keys', + clientId: '599b3553-24b0-416f-9a91-3866d1197e90', }; export const devSkjemabyggingProxy: Partial = { - url: "https://skjemabygging-proxy.dev-fss-pub.nais.io", - clientId: "95170319-b4d7-4190-8271-118ed19bafbf", + url: 'https://skjemabygging-proxy.dev-fss-pub.nais.io', + clientId: '95170319-b4d7-4190-8271-118ed19bafbf', }; export const devFormio: Partial = { - projectUrl: "https://formio-api.intern.dev.nav.no/jvcemxwcpghcqjn", + projectUrl: 'https://formio-api.intern.dev.nav.no/jvcemxwcpghcqjn', }; export const devFyllut: FyllutConfig = { - baseUrl: "https://skjemadelingslenke.ekstern.dev.nav.no/fyllut", + baseUrl: 'https://skjemadelingslenke.ekstern.dev.nav.no/fyllut', }; export const devPusher: Partial = { - cluster: "eu", + cluster: 'eu', }; export const devGithub: Partial = { - name: "skjemautfylling-formio", - owner: "navikt", - base: "test-publishing", + name: 'skjemautfylling-formio', + owner: 'navikt', + base: 'test-publishing', }; export const devGithubApp: Partial = { - appId: "test", + appId: 'test', }; -export const devEnabledFeatures = "translations,diff"; +export const devEnabledFeatures = 'translations,diff'; diff --git a/packages/bygger-backend/src/config/index.ts b/packages/bygger-backend/src/config/index.ts index ba1a5f3ae..572e2bc43 100644 --- a/packages/bygger-backend/src/config/index.ts +++ b/packages/bygger-backend/src/config/index.ts @@ -1,5 +1,5 @@ -import { featureUtils } from "@navikt/skjemadigitalisering-shared-domain"; -import dotenv from "dotenv"; +import { featureUtils } from '@navikt/skjemadigitalisering-shared-domain'; +import dotenv from 'dotenv'; import { devAzure, devEnabledFeatures, @@ -9,22 +9,22 @@ import { devGithubApp, devPusher, devSkjemabyggingProxy, -} from "./development"; -import { ConfigType, NodeEnv } from "./types"; +} from './development'; +import { ConfigType, NodeEnv } from './types'; const nodeEnv = process.env.NODE_ENV as NodeEnv; -if (nodeEnv !== "test") { +if (nodeEnv !== 'test') { dotenv.config(); } const env = (name: string, devValue?: string): string => { const value = process.env[name]; const exists = !!value; - if (nodeEnv === "production" && !exists) { + if (nodeEnv === 'production' && !exists) { throw new Error(`Missing env var: ${name}`); } - if (nodeEnv === "development" && !exists && devValue) { + if (nodeEnv === 'development' && !exists && devValue) { return devValue; } return value!; @@ -36,56 +36,56 @@ const optionalEnv = (name: string): string | undefined => { const config: ConfigType = { azure: { - openidTokenEndpoint: env("AZURE_OPENID_CONFIG_TOKEN_ENDPOINT", devAzure.openidTokenEndpoint), - openidConfigJwksUri: env("AZURE_OPENID_CONFIG_JWKS_URI", devAzure.openidConfigJwksUri), - openidConfigIssuer: env("AZURE_OPENID_CONFIG_ISSUER"), - clientId: env("AZURE_APP_CLIENT_ID", devAzure.clientId), - clientSecret: env("AZURE_APP_CLIENT_SECRET"), + openidTokenEndpoint: env('AZURE_OPENID_CONFIG_TOKEN_ENDPOINT', devAzure.openidTokenEndpoint), + openidConfigJwksUri: env('AZURE_OPENID_CONFIG_JWKS_URI', devAzure.openidConfigJwksUri), + openidConfigIssuer: env('AZURE_OPENID_CONFIG_ISSUER'), + clientId: env('AZURE_APP_CLIENT_ID', devAzure.clientId), + clientSecret: env('AZURE_APP_CLIENT_SECRET'), }, - gitSha: env("GIT_SHA", "unknown-development-git-sha"), + gitSha: env('GIT_SHA', 'unknown-development-git-sha'), skjemabyggingProxy: { - url: env("SKJEMABYGGING_PROXY_URL", devSkjemabyggingProxy.url), - clientId: env("SKJEMABYGGING_PROXY_CLIENT_ID", devSkjemabyggingProxy.clientId), + url: env('SKJEMABYGGING_PROXY_URL', devSkjemabyggingProxy.url), + clientId: env('SKJEMABYGGING_PROXY_CLIENT_ID', devSkjemabyggingProxy.clientId), }, publishRepo: { - name: env("PUBLISH_REPO", devGithub.name), - token: optionalEnv("GITHUB_ACCESS_TOKEN"), - owner: env("PUBLISH_REPO_OWNER", devGithub.owner), - base: env("PUBLISH_REPO_BASE", devGithub.base), + name: env('PUBLISH_REPO', devGithub.name), + token: optionalEnv('GITHUB_ACCESS_TOKEN'), + owner: env('PUBLISH_REPO_OWNER', devGithub.owner), + base: env('PUBLISH_REPO_BASE', devGithub.base), }, githubApp: { - appId: env("GITHUB_APP_ID", devGithubApp.appId), - privateKey: env("GITHUB_APP_PRIVATE_KEY"), - clientId: env("GITHUB_CLIENT_ID"), - clientSecret: env("GITHUB_CLIENT_SECRET"), - installationId: env("GITHUB_APP_INSTALLATION_ID"), + appId: env('GITHUB_APP_ID', devGithubApp.appId), + privateKey: env('GITHUB_APP_PRIVATE_KEY'), + clientId: env('GITHUB_CLIENT_ID'), + clientSecret: env('GITHUB_CLIENT_SECRET'), + installationId: env('GITHUB_APP_INSTALLATION_ID'), }, formio: { - projectUrl: env("FORMIO_PROJECT_URL", devFormio.projectUrl), - projectId: env("FORMIO_PROJECT_ID"), + projectUrl: env('FORMIO_PROJECT_URL', devFormio.projectUrl), + projectId: env('FORMIO_PROJECT_ID'), roleIds: { - administrator: env("FORMIO_ROLE_ID_ADMINISTRATOR"), - authenticated: env("FORMIO_ROLE_ID_AUTHENTICATED"), + administrator: env('FORMIO_ROLE_ID_ADMINISTRATOR'), + authenticated: env('FORMIO_ROLE_ID_AUTHENTICATED'), }, formIds: { - userResource: env("FORMIO_FORM_ID_USER"), + userResource: env('FORMIO_FORM_ID_USER'), }, - jwtSecret: env("FORMIO_JWT_SECRET"), + jwtSecret: env('FORMIO_JWT_SECRET'), }, fyllut: { - baseUrl: env("FYLLUT_BASE_URL", devFyllut.baseUrl), + baseUrl: env('FYLLUT_BASE_URL', devFyllut.baseUrl), }, pusher: { - cluster: env("PUSHER_CLUSTER", devPusher.cluster), - key: env("PUSHER_KEY"), - app: env("PUSHER_APP"), - secret: env("PUSHER_SECRET"), + cluster: env('PUSHER_CLUSTER', devPusher.cluster), + key: env('PUSHER_KEY'), + app: env('PUSHER_APP'), + secret: env('PUSHER_SECRET'), }, nodeEnv, - port: parseInt(process.env.PORT || "8080"), - isProduction: nodeEnv === "production", - isDevelopment: nodeEnv === "development", - featureToggles: featureUtils.toFeatureToggles(env("ENABLED_FEATURES", devEnabledFeatures)), + port: parseInt(process.env.PORT || '8080'), + isProduction: nodeEnv === 'production', + isDevelopment: nodeEnv === 'development', + featureToggles: featureUtils.toFeatureToggles(env('ENABLED_FEATURES', devEnabledFeatures)), }; export default config; diff --git a/packages/bygger-backend/src/config/types.d.ts b/packages/bygger-backend/src/config/types.d.ts index 7815cb970..28b18f073 100644 --- a/packages/bygger-backend/src/config/types.d.ts +++ b/packages/bygger-backend/src/config/types.d.ts @@ -45,7 +45,7 @@ export type GithubAppConfig = { installationId: string; }; -export type NodeEnv = "production" | "development" | "test"; +export type NodeEnv = 'production' | 'development' | 'test'; export type ConfigType = { azure: AzureConfig; diff --git a/packages/bygger-backend/src/context.js b/packages/bygger-backend/src/context.js index 5636183fc..e47a2e6c6 100644 --- a/packages/bygger-backend/src/context.js +++ b/packages/bygger-backend/src/context.js @@ -1,7 +1,7 @@ -import path from "path"; -import { fileURLToPath } from "url"; +import path from 'path'; +import { fileURLToPath } from 'url'; const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); -export const buildDirectory = path.join(dirname, process.env.BYGGER_BUILD_DIR || "../build"); -export const buildDirectoryIndexHtml = path.join(buildDirectory, "index.html"); +export const buildDirectory = path.join(dirname, process.env.BYGGER_BUILD_DIR || '../build'); +export const buildDirectoryIndexHtml = path.join(buildDirectory, 'index.html'); diff --git a/packages/bygger-backend/src/fetchUtils.ts b/packages/bygger-backend/src/fetchUtils.ts index 36cc1d82e..4bcf7b1bf 100644 --- a/packages/bygger-backend/src/fetchUtils.ts +++ b/packages/bygger-backend/src/fetchUtils.ts @@ -1,4 +1,4 @@ -import fetch, { RequestInfo, RequestInit, Response } from "node-fetch"; +import fetch, { RequestInfo, RequestInit, Response } from 'node-fetch'; export class HttpError extends Error { readonly response: Response; @@ -13,26 +13,26 @@ export class HttpError extends Error { export async function fetchWithErrorHandling(url: RequestInfo, options: RequestInit) { const res = await fetch(url, options); if (!res.ok) { - console.error(`Fetch ${options.method || "GET"} ${url} failed with status: ${res.status}`); + console.error(`Fetch ${options.method || 'GET'} ${url} failed with status: ${res.status}`); console.error(`${options.method} body: ${options.body}`); throw new HttpError(res); } if (res.status === 204) { return { - status: "OK", + status: 'OK', data: null, }; } return { - status: "OK", + status: 'OK', data: await res.json(), }; } export function stringTobase64(str: string) { - return Buffer.from(str).toString("base64"); + return Buffer.from(str).toString('base64'); } export function base64ToString(str: string) { - return Buffer.from(str, "base64").toString(); + return Buffer.from(str, 'base64').toString(); } diff --git a/packages/bygger-backend/src/logging/logger.ts b/packages/bygger-backend/src/logging/logger.ts index 69e5c04cf..0cb5719fc 100644 --- a/packages/bygger-backend/src/logging/logger.ts +++ b/packages/bygger-backend/src/logging/logger.ts @@ -1,5 +1,5 @@ -import correlator from "express-correlation-id"; -import { createLogger, format, transports } from "winston"; +import correlator from 'express-correlation-id'; +import { createLogger, format, transports } from 'winston'; const correlationIdFormat = format((info) => { info.correlation_id = correlator.getId(); @@ -7,8 +7,8 @@ const correlationIdFormat = format((info) => { }); export const logger = createLogger({ - level: process.env.BYGGER_BACKEND_LOGLEVEL || (process.env.NODE_ENV === "test" ? "warning" : "info"), - silent: process.env.NODE_ENV === "test", + level: process.env.BYGGER_BACKEND_LOGLEVEL || (process.env.NODE_ENV === 'test' ? 'warning' : 'info'), + silent: process.env.NODE_ENV === 'test', format: format.combine(correlationIdFormat(), format.json()), transports: [new transports.Console()], }); diff --git a/packages/bygger-backend/src/middleware/authHandler.test.ts b/packages/bygger-backend/src/middleware/authHandler.test.ts index 1bab99785..9a8e3f0c1 100644 --- a/packages/bygger-backend/src/middleware/authHandler.test.ts +++ b/packages/bygger-backend/src/middleware/authHandler.test.ts @@ -1,8 +1,8 @@ -import nock from "nock"; -import jose from "node-jose"; -import { createMockJwt, generateJwk, mockRequest, mockResponse } from "../test/testHelpers"; -import { ByggerRequest } from "../types"; -import authHandler from "./authHandler"; +import nock from 'nock'; +import jose from 'node-jose'; +import { createMockJwt, generateJwk, mockRequest, mockResponse } from '../test/testHelpers'; +import { ByggerRequest } from '../types'; +import authHandler from './authHandler'; const byggerAzureClientId = process.env.AZURE_APP_CLIENT_ID!; const byggerAzureIssuer = process.env.AZURE_OPENID_CONFIG_ISSUER!; @@ -10,15 +10,15 @@ const byggerAzureIssuer = process.env.AZURE_OPENID_CONFIG_ISSUER!; const defaultPayload = { aud: byggerAzureClientId, iss: byggerAzureIssuer, - name: "Jon", + name: 'Jon', }; -describe("authHandler", () => { +describe('authHandler', () => { let key: jose.JWK.Key; beforeAll(async () => { key = await generateJwk(); - nock("https://login.unittest.no") - .get("/tenant-id/discovery/v2.0/keys") + nock('https://login.unittest.no') + .get('/tenant-id/discovery/v2.0/keys') .reply(200, { keys: [key.toJSON(false)] }); }); @@ -26,7 +26,7 @@ describe("authHandler", () => { vi.restoreAllMocks(); }); - it("rejects request when authorization header is missing", async () => { + it('rejects request when authorization header is missing', async () => { console.error = vi.fn(); console.log = vi.fn(); const req = mockRequest({}) as ByggerRequest; @@ -37,9 +37,9 @@ describe("authHandler", () => { expect(res.sendStatus).toHaveBeenCalledWith(401); }); - it("rejects request when jwt is (soon) expired", async () => { + it('rejects request when jwt is (soon) expired', async () => { const req = mockRequest({ - headers: { Authorization: `Bearer ${await createMockJwt(defaultPayload, key, "5s")}` }, + headers: { Authorization: `Bearer ${await createMockJwt(defaultPayload, key, '5s')}` }, }) as ByggerRequest; const res = mockResponse(); const next = vi.fn(); @@ -48,8 +48,8 @@ describe("authHandler", () => { expect(res.sendStatus).toHaveBeenCalledWith(401); }); - it("rejects request when audience is wrong", async () => { - const token = await createMockJwt({ ...defaultPayload, aud: "random" }, key, "5s"); + it('rejects request when audience is wrong', async () => { + const token = await createMockJwt({ ...defaultPayload, aud: 'random' }, key, '5s'); const req = mockRequest({ headers: { Authorization: `Bearer ${token}` }, }) as ByggerRequest; @@ -60,7 +60,7 @@ describe("authHandler", () => { expect(res.sendStatus).toHaveBeenCalledWith(401); }); - it("parses jwt and puts user info on request", async () => { + it('parses jwt and puts user info on request', async () => { const req = mockRequest({ headers: { Authorization: `Bearer ${await createMockJwt(defaultPayload, key)}` }, }) as ByggerRequest; diff --git a/packages/bygger-backend/src/middleware/authHandler.ts b/packages/bygger-backend/src/middleware/authHandler.ts index 450115f6d..06ccec1e6 100644 --- a/packages/bygger-backend/src/middleware/authHandler.ts +++ b/packages/bygger-backend/src/middleware/authHandler.ts @@ -1,11 +1,11 @@ -import { NextFunction, Request, Response } from "express"; -import { createRemoteJWKSet, FlattenedJWSInput, JWSHeaderParameters, jwtVerify } from "jose"; -import { GetKeyFunction } from "jose/dist/types/types"; -import jwt from "jsonwebtoken"; -import config from "../config"; -import { AzureAdTokenPayload, User } from "../types/custom"; -import { getDevUser } from "../util/devUser"; -import { adGroups } from "./azureAd"; +import { NextFunction, Request, Response } from 'express'; +import { FlattenedJWSInput, JWSHeaderParameters, createRemoteJWKSet, jwtVerify } from 'jose'; +import { GetKeyFunction } from 'jose/dist/types/types'; +import jwt from 'jsonwebtoken'; +import config from '../config'; +import { AzureAdTokenPayload, User } from '../types/custom'; +import { getDevUser } from '../util/devUser'; +import { adGroups } from './azureAd'; function toExpiredDateString(exp?: number) { if (exp) { @@ -22,7 +22,7 @@ const getAzureRemoteJWKSet: GetKeyFunction => { const verified = await jwtVerify(token, getAzureRemoteJWKSet, { - algorithms: ["RS256"], + algorithms: ['RS256'], issuer: config.azure.openidConfigIssuer, audience: config.azure.clientId, }); @@ -34,24 +34,24 @@ const authHandler = async (req: Request, res: Response, next: NextFunction) => { const user: User = await getDevUser(req); req.getUser = () => user; } else { - const authHeader = req.header("Authorization"); - const token = authHeader && authHeader.split(" ")[1]; + const authHeader = req.header('Authorization'); + const token = authHeader && authHeader.split(' ')[1]; if (!token) { - console.error("Missing jwt token"); + console.error('Missing jwt token'); return res.sendStatus(401); } - console.log("Verifying jwt token signature..."); + console.log('Verifying jwt token signature...'); let tokenPayload: AzureAdTokenPayload; try { tokenPayload = await verifyToken(token); } catch (err) { - console.error("Failed to verify jwt token signature", err); + console.error('Failed to verify jwt token signature', err); return res.sendStatus(401); } if (!tokenPayload) { - console.error("Error decoding jwt token"); + console.error('Error decoding jwt token'); return res.sendStatus(401); } const currentTime = new Date().getTime() / 1000; @@ -90,7 +90,7 @@ export const createFormioJwt = (user: User) => { roles: [formio.roleIds.authenticated], }, }; - return jwt.sign(tokenPayload, formio.jwtSecret, { expiresIn: "9h" }); + return jwt.sign(tokenPayload, formio.jwtSecret, { expiresIn: '9h' }); }; export default authHandler; diff --git a/packages/bygger-backend/src/middleware/authorizedPusher.ts b/packages/bygger-backend/src/middleware/authorizedPusher.ts index fd36ce20a..948cfe459 100644 --- a/packages/bygger-backend/src/middleware/authorizedPusher.ts +++ b/packages/bygger-backend/src/middleware/authorizedPusher.ts @@ -1,16 +1,16 @@ -import bcrypt from "bcryptjs"; -import { NextFunction, Request, Response } from "express"; -import config from "../config"; -import { UnauthorizedError } from "../routers/api/helpers/errors"; +import bcrypt from 'bcryptjs'; +import { NextFunction, Request, Response } from 'express'; +import config from '../config'; +import { UnauthorizedError } from '../routers/api/helpers/errors'; const authorizedPusher = async (req: Request, res: Response, next: NextFunction) => { - const pusherSecretHash = req.get("Bygger-Pusher-Secret-Hash"); + const pusherSecretHash = req.get('Bygger-Pusher-Secret-Hash'); if (!pusherSecretHash) { - next(new UnauthorizedError("Missing pusher secret hash")); + next(new UnauthorizedError('Missing pusher secret hash')); return; } if (!bcrypt.compareSync(config.pusher.secret, pusherSecretHash)) { - next(new UnauthorizedError("Invalid pusher secret")); + next(new UnauthorizedError('Invalid pusher secret')); return; } next(); diff --git a/packages/bygger-backend/src/middleware/azureAd.ts b/packages/bygger-backend/src/middleware/azureAd.ts index 0def9f8f9..f639d0f2d 100644 --- a/packages/bygger-backend/src/middleware/azureAd.ts +++ b/packages/bygger-backend/src/middleware/azureAd.ts @@ -1,9 +1,9 @@ -import { RequestHandler } from "express"; -import { UnauthorizedError } from "../routers/api/helpers/errors"; +import { RequestHandler } from 'express'; +import { UnauthorizedError } from '../routers/api/helpers/errors'; const adGroups = { - USER: "1d12af59-d953-4f85-9f65-d8cbf6672deb", - ADMINISTRATOR: "0c0e4023-5fd3-4cfe-8b40-3b98645bb08f", + USER: '1d12af59-d953-4f85-9f65-d8cbf6672deb', + ADMINISTRATOR: '0c0e4023-5fd3-4cfe-8b40-3b98645bb08f', }; const adHandlers: RequestHandlers = { @@ -11,7 +11,7 @@ const adHandlers: RequestHandlers = { if (req.getUser().isAdmin) { next(); } else { - next(new UnauthorizedError("User is not administrator")); + next(new UnauthorizedError('User is not administrator')); } }, }; diff --git a/packages/bygger-backend/src/middleware/ratelimit.ts b/packages/bygger-backend/src/middleware/ratelimit.ts index c4fdaa6f5..6f44fdf36 100644 --- a/packages/bygger-backend/src/middleware/ratelimit.ts +++ b/packages/bygger-backend/src/middleware/ratelimit.ts @@ -1,4 +1,4 @@ -import rateLimit from "express-rate-limit"; +import rateLimit from 'express-rate-limit'; const MS_ONE_MINUTE = 60 * 1000; @@ -6,7 +6,7 @@ export const rateLimiter = (windowMs: number, max: number) => rateLimit({ windowMs, max, - message: "Too many requests from IP", + message: 'Too many requests from IP', standardHeaders: true, legacyHeaders: false, }); diff --git a/packages/bygger-backend/src/migration/FormMigrationLogger.test.ts b/packages/bygger-backend/src/migration/FormMigrationLogger.test.ts index 68c4f3885..530c47951 100644 --- a/packages/bygger-backend/src/migration/FormMigrationLogger.test.ts +++ b/packages/bygger-backend/src/migration/FormMigrationLogger.test.ts @@ -1,7 +1,7 @@ -import { Component, DependencyType } from "@navikt/skjemadigitalisering-shared-domain"; -import { FormMigrationLogData } from "../types/migration"; -import FormMigrationLogger from "./FormMigrationLogger"; -import { componentWithSimpleConditionalToRadio, formWithSimpleConditionalToRadio, radioComponent } from "./testData"; +import { Component, DependencyType } from '@navikt/skjemadigitalisering-shared-domain'; +import { FormMigrationLogData } from '../types/migration'; +import FormMigrationLogger from './FormMigrationLogger'; +import { componentWithSimpleConditionalToRadio, formWithSimpleConditionalToRadio, radioComponent } from './testData'; const idKeyAndLabel = (identifier: string): Component => ({ @@ -10,25 +10,25 @@ const idKeyAndLabel = (identifier: string): Component => label: `label-${identifier}`, }) as unknown as Component; -describe("FormMigrationLogger", () => { +describe('FormMigrationLogger', () => { let logger: FormMigrationLogger; beforeEach(() => { logger = new FormMigrationLogger(formWithSimpleConditionalToRadio); }); - describe("getLog", () => { - it("contains title, path and key properties from the form", () => { + describe('getLog', () => { + it('contains title, path and key properties from the form', () => { const { name, path, title, properties } = formWithSimpleConditionalToRadio; expect(logger.getLog()).toEqual(expect.objectContaining({ name, path, title, ...properties })); }); - describe("When all entries contains identical original and new components", () => { + describe('When all entries contains identical original and new components', () => { let log: FormMigrationLogData; beforeEach(() => { - logger.add(idKeyAndLabel("a"), idKeyAndLabel("a")); - logger.add(idKeyAndLabel("b"), idKeyAndLabel("b")); - logger.add(idKeyAndLabel("c"), idKeyAndLabel("c")); + logger.add(idKeyAndLabel('a'), idKeyAndLabel('a')); + logger.add(idKeyAndLabel('b'), idKeyAndLabel('b')); + logger.add(idKeyAndLabel('c'), idKeyAndLabel('c')); log = logger.getLog(); }); @@ -40,25 +40,25 @@ describe("FormMigrationLogger", () => { expect(log.changed).toBe(0); }); - it("diff contains all added entries", () => { + it('diff contains all added entries', () => { expect(log.diff).toHaveLength(3); }); }); - describe("When added entries includes changed compoenntes", () => { + describe('When added entries includes changed compoenntes', () => { let log: FormMigrationLogData; - const componentA = idKeyAndLabel("a"); - const componentB = idKeyAndLabel("b"); - const noChanges = idKeyAndLabel("no-changes"); + const componentA = idKeyAndLabel('a'); + const componentB = idKeyAndLabel('b'); + const noChanges = idKeyAndLabel('no-changes'); beforeEach(() => { logger.add( - { ...componentA, customProperty: "old value" } as Component, - { ...componentA, customProperty: "new value" } as Component, + { ...componentA, customProperty: 'old value' } as Component, + { ...componentA, customProperty: 'new value' } as Component, ); - logger.add(idKeyAndLabel("no-changes"), idKeyAndLabel("no-changes")); + logger.add(idKeyAndLabel('no-changes'), idKeyAndLabel('no-changes')); logger.add( - { ...componentB, customProperty: "old value" } as Component, - { ...componentB, customProperty: "new value" } as Component, + { ...componentB, customProperty: 'old value' } as Component, + { ...componentB, customProperty: 'new value' } as Component, ); log = logger.getLog(); }); @@ -71,33 +71,33 @@ describe("FormMigrationLogger", () => { expect(log.changed).toBe(2); }); - it("diff contains entries for each changed and unchanged components component", () => { + it('diff contains entries for each changed and unchanged components component', () => { expect(log.diff).toEqual([ expect.objectContaining({ key: componentA.key, - customProperty_ORIGINAL: "old value", - customProperty_NEW: "new value", + customProperty_ORIGINAL: 'old value', + customProperty_NEW: 'new value', }), noChanges, expect.objectContaining({ key: componentB.key, - customProperty_ORIGINAL: "old value", - customProperty_NEW: "new value", + customProperty_ORIGINAL: 'old value', + customProperty_NEW: 'new value', }), ]); }); }); }); - describe("getDependencies", () => { - it("returns dependencies", () => { + describe('getDependencies', () => { + it('returns dependencies', () => { const { key, label } = radioComponent; - const dependency = { key, label, types: ["conditional"] as DependencyType[], matchesFilters: false }; + const dependency = { key, label, types: ['conditional'] as DependencyType[], matchesFilters: false }; logger.add( componentWithSimpleConditionalToRadio, { ...componentWithSimpleConditionalToRadio, - label: "New Label", + label: 'New Label', }, [dependency], ); @@ -105,24 +105,24 @@ describe("FormMigrationLogger", () => { expect(logger.getDependencies()).toEqual({ [componentWithSimpleConditionalToRadio.key]: [dependency] }); }); - it("returns nothing when no dependencies were added", () => { + it('returns nothing when no dependencies were added', () => { logger.add(componentWithSimpleConditionalToRadio, { ...componentWithSimpleConditionalToRadio, - label: "New Label", + label: 'New Label', }); expect(logger.getDependencies()).toEqual({}); }); }); - describe("getBreakingChanges", () => { - it("lists components with dependencies when changing key", () => { + describe('getBreakingChanges', () => { + it('lists components with dependencies when changing key', () => { const { id, key, label } = radioComponent; - logger.add(radioComponent, { ...radioComponent, key: "changed-key" }); + logger.add(radioComponent, { ...radioComponent, key: 'changed-key' }); expect(logger.getBreakingChanges()).toEqual([ { componentWithDependencies: { id, - key_NEW: "changed-key", + key_NEW: 'changed-key', key_ORIGINAL: key, label, }, @@ -136,8 +136,8 @@ describe("FormMigrationLogger", () => { ]); }); - it("lists components with dependencies when changing values", () => { - const newValues = [{ value: "kanskje", label: "Kanskje" }]; + it('lists components with dependencies when changing values', () => { + const newValues = [{ value: 'kanskje', label: 'Kanskje' }]; logger.add(radioComponent, { ...radioComponent, values: newValues } as Component); expect(logger.getBreakingChanges()).toEqual([ { @@ -154,11 +154,11 @@ describe("FormMigrationLogger", () => { ]); }); - it("does not list components with dependencies when changing other properties, as they are not breaking changes", () => { - logger.add(radioComponent, { ...radioComponent, type: "video" }); + it('does not list components with dependencies when changing other properties, as they are not breaking changes', () => { + logger.add(radioComponent, { ...radioComponent, type: 'video' }); logger.add(radioComponent, { ...radioComponent, - newProperty: "new value", + newProperty: 'new value', } as unknown as Component); expect(logger.getBreakingChanges()).toEqual([]); }); diff --git a/packages/bygger-backend/src/migration/FormMigrationLogger.ts b/packages/bygger-backend/src/migration/FormMigrationLogger.ts index 7ba07d957..69d785692 100644 --- a/packages/bygger-backend/src/migration/FormMigrationLogger.ts +++ b/packages/bygger-backend/src/migration/FormMigrationLogger.ts @@ -1,12 +1,12 @@ -import { Component, NavFormType, navFormUtils } from "@navikt/skjemadigitalisering-shared-domain"; +import { Component, NavFormType, navFormUtils } from '@navikt/skjemadigitalisering-shared-domain'; import { BreakingChanges, DependeeComponent, Dependencies, FormMigrationDiff, FormMigrationLogData, -} from "../types/migration"; -import { generateDiff } from "./diffingTool"; +} from '../types/migration'; +import { generateDiff } from './diffingTool'; interface AffectedComponent { key: string; diff --git a/packages/bygger-backend/src/migration/diffingTool.js b/packages/bygger-backend/src/migration/diffingTool.js index 965d0bae3..be700b50e 100644 --- a/packages/bygger-backend/src/migration/diffingTool.js +++ b/packages/bygger-backend/src/migration/diffingTool.js @@ -1,9 +1,9 @@ function generateDiff(originalComponent, editedComponent) { return Object.keys({ ...originalComponent, ...editedComponent }).reduce((acc, key) => { - if (key === "id") return { ...acc, [key]: originalComponent[key] }; + if (key === 'id') return { ...acc, [key]: originalComponent[key] }; if (originalComponent[key] !== editedComponent[key]) { if ( - typeof originalComponent[key] === "object" && + typeof originalComponent[key] === 'object' && !Array.isArray(originalComponent[key]) && originalComponent[key] !== null ) { @@ -18,7 +18,7 @@ function generateDiff(originalComponent, editedComponent) { [`${key}_NEW`]: editedComponent[key], }; } - if (key === "key" || key === "label") return { ...acc, [key]: originalComponent[key] }; + if (key === 'key' || key === 'label') return { ...acc, [key]: originalComponent[key] }; return acc; }, {}); } diff --git a/packages/bygger-backend/src/migration/diffingTool.test.js b/packages/bygger-backend/src/migration/diffingTool.test.js index 809f2e944..844cb0b3c 100644 --- a/packages/bygger-backend/src/migration/diffingTool.test.js +++ b/packages/bygger-backend/src/migration/diffingTool.test.js @@ -1,141 +1,141 @@ -import { generateDiff } from "./diffingTool"; +import { generateDiff } from './diffingTool'; -describe("diffingTool", () => { - it("returns empty object when the two versions are identical", () => { - const actual = generateDiff({ value: "a value" }, { value: "a value" }); +describe('diffingTool', () => { + it('returns empty object when the two versions are identical', () => { + const actual = generateDiff({ value: 'a value' }, { value: 'a value' }); expect(actual).toEqual({}); }); - it("lists the original and the new value if a property is different in the two versions", () => { - const actual = generateDiff({ value: "the original value" }, { value: "the new value" }); + it('lists the original and the new value if a property is different in the two versions', () => { + const actual = generateDiff({ value: 'the original value' }, { value: 'the new value' }); expect(actual).toEqual({ - value_NEW: "the new value", - value_ORIGINAL: "the original value", + value_NEW: 'the new value', + value_ORIGINAL: 'the original value', }); }); - it("lists original and new values of all properties that have changed", () => { + it('lists original and new values of all properties that have changed', () => { const actual = generateDiff( - { value1: "the original value 1", value2: "the original value 2" }, - { value1: "the new value 1", value2: "the new value 2" }, + { value1: 'the original value 1', value2: 'the original value 2' }, + { value1: 'the new value 1', value2: 'the new value 2' }, ); expect(actual).toEqual({ - value1_NEW: "the new value 1", - value1_ORIGINAL: "the original value 1", - value2_NEW: "the new value 2", - value2_ORIGINAL: "the original value 2", + value1_NEW: 'the new value 1', + value1_ORIGINAL: 'the original value 1', + value2_NEW: 'the new value 2', + value2_ORIGINAL: 'the original value 2', }); }); - it("lists only changes for properties that have changed values, not the others", () => { + it('lists only changes for properties that have changed values, not the others', () => { const actual = generateDiff( - { value1: "the original value 1", value2: "the same value 2" }, - { value1: "the new value 1", value2: "the same value 2" }, + { value1: 'the original value 1', value2: 'the same value 2' }, + { value1: 'the new value 1', value2: 'the same value 2' }, ); expect(actual).toEqual({ - value1_NEW: "the new value 1", - value1_ORIGINAL: "the original value 1", + value1_NEW: 'the new value 1', + value1_ORIGINAL: 'the original value 1', }); }); - it("will diff nested objects", () => { + it('will diff nested objects', () => { const actual = generateDiff( { nested: { - value: "original nested value", + value: 'original nested value', }, }, { nested: { - value: "new nested value", + value: 'new nested value', }, }, ); expect(actual).toEqual({ nested: { - value_NEW: "new nested value", - value_ORIGINAL: "original nested value", + value_NEW: 'new nested value', + value_ORIGINAL: 'original nested value', }, }); }); - it("lists only changes in nested objects that have changed", () => { + it('lists only changes in nested objects that have changed', () => { const actual = generateDiff( { - same: "same value", + same: 'same value', nested: { - value: "original nested value", - same: "same nested value", + value: 'original nested value', + same: 'same nested value', }, }, { - same: "same value", + same: 'same value', nested: { - value: "new nested value", - same: "same nested value", + value: 'new nested value', + same: 'same nested value', }, }, ); expect(actual).toEqual({ nested: { - value_NEW: "new nested value", - value_ORIGINAL: "original nested value", + value_NEW: 'new nested value', + value_ORIGINAL: 'original nested value', }, }); }); - it("lists changes for different levels of nesting at the same time", () => { + it('lists changes for different levels of nesting at the same time', () => { const actual = generateDiff( { - same: "same value", - value: "original value", + same: 'same value', + value: 'original value', nested: { - value: "original nested value", - same: "same nested value", + value: 'original nested value', + same: 'same nested value', }, }, { - same: "same value", - value: "new value", + same: 'same value', + value: 'new value', nested: { - value: "new nested value", - same: "same nested value", + value: 'new nested value', + same: 'same nested value', }, }, ); expect(actual).toEqual({ - value_NEW: "new value", - value_ORIGINAL: "original value", + value_NEW: 'new value', + value_ORIGINAL: 'original value', nested: { - value_NEW: "new nested value", - value_ORIGINAL: "original nested value", + value_NEW: 'new nested value', + value_ORIGINAL: 'original nested value', }, }); }); - it("will show diff for changes to key or label, but not id", () => { + it('will show diff for changes to key or label, but not id', () => { const actual = generateDiff( { - id: "original id", - key: "original key", - label: "original label", + id: 'original id', + key: 'original key', + label: 'original label', }, { - id: "new ID", - key: "new key", - label: "new label", + id: 'new ID', + key: 'new key', + label: 'new label', }, ); expect(actual).toEqual({ - id: "original id", - key_NEW: "new key", - key_ORIGINAL: "original key", - label_NEW: "new label", - label_ORIGINAL: "original label", + id: 'original id', + key_NEW: 'new key', + key_ORIGINAL: 'original key', + label_NEW: 'new label', + label_ORIGINAL: 'original label', }); }); }); diff --git a/packages/bygger-backend/src/migration/filterUtils.test.ts b/packages/bygger-backend/src/migration/filterUtils.test.ts index 544ca0382..0ba0c7759 100644 --- a/packages/bygger-backend/src/migration/filterUtils.test.ts +++ b/packages/bygger-backend/src/migration/filterUtils.test.ts @@ -2,91 +2,91 @@ import { componentHasDependencyMatchingFilters, componentMatchesFilters, getPropertyFromComponent, -} from "./filterUtils"; +} from './filterUtils'; import { componentWithAdvancedConditionalToRadio, componentWithSimpleConditionalToRadio, formWithSimpleConditionalToRadio, originalTextFieldComponent, -} from "./testData"; +} from './testData'; -describe("filterUtils", () => { - describe("getPropertyFromComponent", () => { - it("gets the value of a property in the object as a string", () => { - const actual = getPropertyFromComponent({ value: "the value" }, ["value"]); - expect(actual).toEqual("the value"); +describe('filterUtils', () => { + describe('getPropertyFromComponent', () => { + it('gets the value of a property in the object as a string', () => { + const actual = getPropertyFromComponent({ value: 'the value' }, ['value']); + expect(actual).toBe('the value'); }); - it("gets properties from nested objects", () => { - const actual = getPropertyFromComponent({ firstLevel: { secondLevel: { thirdLevel: { value: "the value" } } } }, [ - "firstLevel", - "secondLevel", - "thirdLevel", - "value", + it('gets properties from nested objects', () => { + const actual = getPropertyFromComponent({ firstLevel: { secondLevel: { thirdLevel: { value: 'the value' } } } }, [ + 'firstLevel', + 'secondLevel', + 'thirdLevel', + 'value', ]); - expect(actual).toEqual("the value"); + expect(actual).toBe('the value'); }); }); - describe("componentMatchesSearchFilters", () => { - it("returns true if all searchFilters matches the related properties in the component", () => { + describe('componentMatchesSearchFilters', () => { + it('returns true if all searchFilters matches the related properties in the component', () => { expect( componentMatchesFilters(originalTextFieldComponent, [ { - key: "fieldSize", - value: "input--xxl", + key: 'fieldSize', + value: 'input--xxl', }, - { key: "validateOn", value: "blur" }, + { key: 'validateOn', value: 'blur' }, ]), ).toBe(true); }); - it("returns false if one searchFilter does not match the related property in the component", () => { + it('returns false if one searchFilter does not match the related property in the component', () => { expect( componentMatchesFilters(originalTextFieldComponent, [ { - key: "fieldSize", - value: "input--s", + key: 'fieldSize', + value: 'input--s', }, - { key: "validateOn", value: "blur" }, + { key: 'validateOn', value: 'blur' }, ]), ).toBe(false); }); - it("matches on nested properties", () => { + it('matches on nested properties', () => { expect( componentMatchesFilters(originalTextFieldComponent, [ { - key: "validate.required", + key: 'validate.required', value: true, }, - { key: "validateOn", value: "blur" }, + { key: 'validateOn', value: 'blur' }, ]), ).toBe(true); expect( componentMatchesFilters(originalTextFieldComponent, [ { - key: "validate.required", + key: 'validate.required', value: false, }, - { key: "validateOn", value: "blur" }, + { key: 'validateOn', value: 'blur' }, ]), ).toBe(false); }); - describe("With operators", () => { - const typeEqTextfield = { key: "type", value: "textfield" }; - const typeEqRadio = { key: "type", value: "radio" }; - const nonExistingProp = { key: "nonExistingProp", value: "" }; + describe('With operators', () => { + const typeEqTextfield = { key: 'type', value: 'textfield' }; + const typeEqRadio = { key: 'type', value: 'radio' }; + const nonExistingProp = { key: 'nonExistingProp', value: '' }; - describe("equals and not equal", () => { + describe('equals and not equal', () => { it("the operator 'eq' (equals) is the same as default", () => { expect(componentMatchesFilters(originalTextFieldComponent, [typeEqTextfield])).toBe(true); expect( componentMatchesFilters(originalTextFieldComponent, [ { ...typeEqTextfield, - operator: "eq", + operator: 'eq', }, ]), ).toBe(true); @@ -96,7 +96,7 @@ describe("filterUtils", () => { componentMatchesFilters(originalTextFieldComponent, [ { ...typeEqRadio, - operator: "eq", + operator: 'eq', }, ]), ).toBe(false); @@ -106,7 +106,7 @@ describe("filterUtils", () => { componentMatchesFilters(originalTextFieldComponent, [ { ...nonExistingProp, - operator: "eq", + operator: 'eq', }, ]), ).toBe(false); @@ -117,7 +117,7 @@ describe("filterUtils", () => { componentMatchesFilters(originalTextFieldComponent, [ { ...typeEqTextfield, - operator: "n_eq", + operator: 'n_eq', }, ]), ).toBe(false); @@ -128,7 +128,7 @@ describe("filterUtils", () => { componentMatchesFilters(originalTextFieldComponent, [ { ...typeEqRadio, - operator: "n_eq", + operator: 'n_eq', }, ]), ).toBe(true); @@ -139,21 +139,21 @@ describe("filterUtils", () => { componentMatchesFilters(originalTextFieldComponent, [ { ...nonExistingProp, - operator: "n_eq", + operator: 'n_eq', }, ]), ).toBe(true); }); }); - describe("exists and not exist", () => { + describe('exists and not exist', () => { it("the operator 'exists' evaluates to false when the property exists", () => { expect( componentMatchesFilters(originalTextFieldComponent, [ { - key: "type", - value: "", - operator: "exists", + key: 'type', + value: '', + operator: 'exists', }, ]), ).toBe(true); @@ -163,9 +163,9 @@ describe("filterUtils", () => { expect( componentMatchesFilters(originalTextFieldComponent, [ { - key: "non-existing-prop", - value: "", - operator: "exists", + key: 'non-existing-prop', + value: '', + operator: 'exists', }, ]), ).toBe(false); @@ -175,9 +175,9 @@ describe("filterUtils", () => { expect( componentMatchesFilters(originalTextFieldComponent, [ { - key: "type", - value: "", - operator: "n_exists", + key: 'type', + value: '', + operator: 'n_exists', }, ]), ).toBe(false); @@ -187,29 +187,29 @@ describe("filterUtils", () => { expect( componentMatchesFilters(originalTextFieldComponent, [ { - key: "non-existing-prop", - value: "", - operator: "n_exists", + key: 'non-existing-prop', + value: '', + operator: 'n_exists', }, ]), ).toBe(true); }); }); - describe("contains and not contain", () => { + describe('contains and not contain', () => { const customComponent = { ...originalTextFieldComponent, - customLongText: "LoremIpsum1234456789!substring-in-custom-long-textqwertyuiop", - customArray: ["a", "b", "member-of-array", "c"], + customLongText: 'LoremIpsum1234456789!substring-in-custom-long-textqwertyuiop', + customArray: ['a', 'b', 'member-of-array', 'c'], }; it("the operator 'contains' evaluates to true when the value is a substring", () => { expect( componentMatchesFilters(customComponent, [ { - key: "customLongText", - value: "substring-in-custom-long-text", - operator: "contains", + key: 'customLongText', + value: 'substring-in-custom-long-text', + operator: 'contains', }, ]), ).toBe(true); @@ -219,9 +219,9 @@ describe("filterUtils", () => { expect( componentMatchesFilters(customComponent, [ { - key: "customLongText", - value: "substring-NOT-in-custom-long-text", - operator: "contains", + key: 'customLongText', + value: 'substring-NOT-in-custom-long-text', + operator: 'contains', }, ]), ).toBe(false); @@ -231,9 +231,9 @@ describe("filterUtils", () => { expect( componentMatchesFilters(customComponent, [ { - key: "customLongText", - value: "substring-in-custom-long-text", - operator: "n_contains", + key: 'customLongText', + value: 'substring-in-custom-long-text', + operator: 'n_contains', }, ]), ).toBe(false); @@ -243,9 +243,9 @@ describe("filterUtils", () => { expect( componentMatchesFilters(customComponent, [ { - key: "customLongText", - value: "substring-NOT-in-custom-long-text", - operator: "n_contains", + key: 'customLongText', + value: 'substring-NOT-in-custom-long-text', + operator: 'n_contains', }, ]), ).toBe(true); @@ -255,9 +255,9 @@ describe("filterUtils", () => { expect( componentMatchesFilters(customComponent, [ { - key: "customArray", - value: "member-of-array", - operator: "contains", + key: 'customArray', + value: 'member-of-array', + operator: 'contains', }, ]), ).toBe(true); @@ -267,21 +267,9 @@ describe("filterUtils", () => { expect( componentMatchesFilters(customComponent, [ { - key: "customArray", - value: "not-a-member-of-array", - operator: "contains", - }, - ]), - ).toBe(false); - }); - - it("the operator 'n_contains' (not contains) evaluates to false when the value is a substring", () => { - expect( - componentMatchesFilters(customComponent, [ - { - key: "customLongText", - value: "substring-in-custom-long-text", - operator: "n_contains", + key: 'customArray', + value: 'not-a-member-of-array', + operator: 'contains', }, ]), ).toBe(false); @@ -291,9 +279,9 @@ describe("filterUtils", () => { expect( componentMatchesFilters(customComponent, [ { - key: "customLongText", - value: "substring-NOT-in-custom-long-text", - operator: "n_contains", + key: 'customLongText', + value: 'substring-NOT-in-custom-long-text', + operator: 'n_contains', }, ]), ).toBe(true); @@ -303,9 +291,9 @@ describe("filterUtils", () => { expect( componentMatchesFilters(originalTextFieldComponent, [ { - key: "customLongText", - value: "substring-NOT-in-custom-long-text", - operator: "contains", + key: 'customLongText', + value: 'substring-NOT-in-custom-long-text', + operator: 'contains', }, ]), ).toBe(false); @@ -315,9 +303,9 @@ describe("filterUtils", () => { expect( componentMatchesFilters(originalTextFieldComponent, [ { - key: "customLongText", - value: "substring-NOT-in-custom-long-text", - operator: "n_contains", + key: 'customLongText', + value: 'substring-NOT-in-custom-long-text', + operator: 'n_contains', }, ]), ).toBe(true); @@ -326,42 +314,42 @@ describe("filterUtils", () => { }); }); - describe("componentHasDependencyMatchingFilters", () => { - it("returns true when component has a simple conditional dependency to a component that matches the filter", () => { + describe('componentHasDependencyMatchingFilters', () => { + it('returns true when component has a simple conditional dependency to a component that matches the filter', () => { expect( componentHasDependencyMatchingFilters(formWithSimpleConditionalToRadio, componentWithSimpleConditionalToRadio, [ - { key: "type", value: "radio" }, + { key: 'type', value: 'radio' }, ]), ).toBe(true); }); - it("returns false when component has a simple conditional dependency to a component that does not match the filter", () => { + it('returns false when component has a simple conditional dependency to a component that does not match the filter', () => { expect( componentHasDependencyMatchingFilters(formWithSimpleConditionalToRadio, componentWithSimpleConditionalToRadio, [ - { key: "type", value: "radio" }, - { key: "disabled", value: "true" }, + { key: 'type', value: 'radio' }, + { key: 'disabled', value: 'true' }, ]), ).toBe(false); }); - it("returns true when component has an advanced conditional dependency to a component that matches the filter", () => { + it('returns true when component has an advanced conditional dependency to a component that matches the filter', () => { expect( componentHasDependencyMatchingFilters( formWithSimpleConditionalToRadio, componentWithAdvancedConditionalToRadio, - [{ key: "type", value: "radio" }], + [{ key: 'type', value: 'radio' }], ), ).toBe(true); }); - it("returns false when component has an advanced conditional dependency to a component that does not match the filter", () => { + it('returns false when component has an advanced conditional dependency to a component that does not match the filter', () => { expect( componentHasDependencyMatchingFilters( formWithSimpleConditionalToRadio, componentWithAdvancedConditionalToRadio, [ - { key: "type", value: "radio" }, - { key: "disabled", value: "true" }, + { key: 'type', value: 'radio' }, + { key: 'disabled', value: 'true' }, ], ), ).toBe(false); diff --git a/packages/bygger-backend/src/migration/filterUtils.ts b/packages/bygger-backend/src/migration/filterUtils.ts index c0009f58d..fdde9fcf0 100644 --- a/packages/bygger-backend/src/migration/filterUtils.ts +++ b/packages/bygger-backend/src/migration/filterUtils.ts @@ -4,8 +4,8 @@ import { NavFormType, navFormUtils, Operator, -} from "@navikt/skjemadigitalisering-shared-domain"; -import { ParsedInput } from "../types/migration"; +} from '@navikt/skjemadigitalisering-shared-domain'; +import { ParsedInput } from '../types/migration'; interface Filter { key: string; @@ -30,19 +30,19 @@ function getPropertyFromComponent(comp: any, properties: string[]): string | und function componentMatchesFilters(component: Component, filters: Filter[]) { return filters.every(({ key, value, operator }) => { switch (operator) { - case "exists": - return !!getPropertyFromComponent(component, key.split(".")); - case "n_exists": - return !getPropertyFromComponent(component, key.split(".")); - case "contains": - return getPropertyFromComponent(component, key.split("."))?.includes(value); - case "n_contains": - return !getPropertyFromComponent(component, key.split("."))?.includes(value); - case "n_eq": - return getPropertyFromComponent(component, key.split(".")) !== value; - case "eq": + case 'exists': + return !!getPropertyFromComponent(component, key.split('.')); + case 'n_exists': + return !getPropertyFromComponent(component, key.split('.')); + case 'contains': + return getPropertyFromComponent(component, key.split('.'))?.includes(value); + case 'n_contains': + return !getPropertyFromComponent(component, key.split('.'))?.includes(value); + case 'n_eq': + return getPropertyFromComponent(component, key.split('.')) !== value; + case 'eq': default: - return getPropertyFromComponent(component, key.split(".")) === value; + return getPropertyFromComponent(component, key.split('.')) === value; } }); } @@ -60,8 +60,8 @@ function componentHasDependencyMatchingFilters( } export { - parseFiltersFromParam, - getPropertyFromComponent, - componentMatchesFilters, componentHasDependencyMatchingFilters, + componentMatchesFilters, + getPropertyFromComponent, + parseFiltersFromParam, }; diff --git a/packages/bygger-backend/src/migration/migrationScripts.js b/packages/bygger-backend/src/migration/migrationScripts.js index caa2ff6a5..76e564ebe 100644 --- a/packages/bygger-backend/src/migration/migrationScripts.js +++ b/packages/bygger-backend/src/migration/migrationScripts.js @@ -1,6 +1,6 @@ -import { navFormUtils, objectUtils } from "@navikt/skjemadigitalisering-shared-domain"; -import FormMigrationLogger from "./FormMigrationLogger"; -import { componentHasDependencyMatchingFilters, componentMatchesFilters, parseFiltersFromParam } from "./filterUtils"; +import { navFormUtils, objectUtils } from '@navikt/skjemadigitalisering-shared-domain'; +import FormMigrationLogger from './FormMigrationLogger'; +import { componentHasDependencyMatchingFilters, componentMatchesFilters, parseFiltersFromParam } from './filterUtils'; function recursivelyMigrateComponentAndSubcomponents( form, @@ -55,7 +55,7 @@ function migrateForm(form, searchFiltersFromParam, dependencyFiltersFromParam, e function getEditScript(editOptions) { const editOptionObjects = Object.entries(editOptions).map(([editOptionKey, editOptionValue]) => - editOptionKey.split(".").reduceRight((acc, currentValue) => { + editOptionKey.split('.').reduceRight((acc, currentValue) => { return { [currentValue]: acc }; }, editOptionValue), ); @@ -97,4 +97,4 @@ async function previewForm(searchFilters, dependencyFilters, editOptions, form) return migratedForm; } -export { migrateForm, migrateForms, getEditScript, previewForm }; +export { getEditScript, migrateForm, migrateForms, previewForm }; diff --git a/packages/bygger-backend/src/migration/migrationScripts.test.js b/packages/bygger-backend/src/migration/migrationScripts.test.js index 6421db142..93a6d545e 100644 --- a/packages/bygger-backend/src/migration/migrationScripts.test.js +++ b/packages/bygger-backend/src/migration/migrationScripts.test.js @@ -1,5 +1,4 @@ -import mockedForm from "./testdata/Form"; -import { getEditScript, migrateForm, migrateForms } from "./migrationScripts"; +import { getEditScript, migrateForm, migrateForms } from './migrationScripts'; import { formWithAdvancedConditionalToRadio, formWithSimpleConditionalToCheckbox, @@ -9,21 +8,22 @@ import { originalPanelComponent, originalSkjemaGruppeComponent, originalTextFieldComponent, -} from "./testData"; +} from './testData'; +import mockedForm from './testdata/Form'; -describe("Migration scripts", () => { - describe("migrateForm", () => { - const fnrEditOptions = { "validate.custom": "valid = instance.newValidateFnr(input)" }; +describe('Migration scripts', () => { + describe('migrateForm', () => { + const fnrEditOptions = { 'validate.custom': 'valid = instance.newValidateFnr(input)' }; - it("can update component based on type", () => { - const { migratedForm: actual } = migrateForm(originalForm, { type: "fnrfield" }, {}, fnrEditOptions); + it('can update component based on type', () => { + const { migratedForm: actual } = migrateForm(originalForm, { type: 'fnrfield' }, {}, fnrEditOptions); expect(actual).toEqual({ ...originalForm, components: [ { ...originalFodselsnummerComponent, validate: { - custom: "valid = instance.newValidateFnr(input)", + custom: 'valid = instance.newValidateFnr(input)', required: true, }, }, @@ -32,10 +32,10 @@ describe("Migration scripts", () => { }); }); - it("can migrate subcomponents", () => { + it('can migrate subcomponents', () => { const { migratedForm: actual } = migrateForm( { - path: "test-form", + path: 'test-form', components: [ { ...originalPanelComponent, @@ -43,13 +43,13 @@ describe("Migration scripts", () => { }, ], }, - { type: "fnrfield" }, + { type: 'fnrfield' }, {}, fnrEditOptions, ); expect(actual).toEqual({ - path: "test-form", + path: 'test-form', components: [ { ...originalPanelComponent, @@ -57,7 +57,7 @@ describe("Migration scripts", () => { { ...originalFodselsnummerComponent, validate: { - custom: "valid = instance.newValidateFnr(input)", + custom: 'valid = instance.newValidateFnr(input)', required: true, }, }, @@ -67,30 +67,30 @@ describe("Migration scripts", () => { }); }); - it("can migrate subcomponents of a migrated component", () => { + it('can migrate subcomponents of a migrated component', () => { const { migratedForm: actual } = migrateForm( { - path: "test-form", + path: 'test-form', components: [ { ...originalSkjemaGruppeComponent, components: [ { ...originalSkjemaGruppeComponent, - key: "subSkjemaGruppe", + key: 'subSkjemaGruppe', components: [originalTextFieldComponent], }, ], }, ], }, - { type: "navSkjemagruppe" }, + { type: 'navSkjemagruppe' }, {}, { modifiedByTest: true }, ); expect(actual).toEqual({ - path: "test-form", + path: 'test-form', components: [ { ...originalSkjemaGruppeComponent, @@ -98,7 +98,7 @@ describe("Migration scripts", () => { components: [ { ...originalSkjemaGruppeComponent, - key: "subSkjemaGruppe", + key: 'subSkjemaGruppe', modifiedByTest: true, components: [originalTextFieldComponent], }, @@ -109,35 +109,35 @@ describe("Migration scripts", () => { }); }); - describe("migrateForms", () => { + describe('migrateForms', () => { const allForms = [ - { ...mockedForm, path: "form1", properties: { skjemanummer: "form1" } }, - { ...mockedForm, path: "form2", properties: { skjemanummer: "form2" } }, - { ...mockedForm, path: "form3", properties: { skjemanummer: "form3" } }, + { ...mockedForm, path: 'form1', properties: { skjemanummer: 'form1' } }, + { ...mockedForm, path: 'form2', properties: { skjemanummer: 'form2' } }, + { ...mockedForm, path: 'form3', properties: { skjemanummer: 'form3' } }, ]; - it("generates log only for included form paths", async () => { - const { log } = await migrateForms({ disabled: false }, {}, { disabled: true }, allForms, ["form1", "form3"]); - expect(Object.keys(log)).toEqual(["form1", "form3"]); + it('generates log only for included form paths', async () => { + const { log } = await migrateForms({ disabled: false }, {}, { disabled: true }, allForms, ['form1', 'form3']); + expect(Object.keys(log)).toEqual(['form1', 'form3']); }); - it("only migrates forms included by the provided formPaths", async () => { + it('only migrates forms included by the provided formPaths', async () => { const { migratedForms } = await migrateForms({ disabled: false }, {}, { disabled: true }, allForms, [ - "form2", - "form3", + 'form2', + 'form3', ]); expect(migratedForms).toHaveLength(2); - expect(migratedForms[0].path).toBe("form2"); - expect(migratedForms[1].path).toBe("form3"); + expect(migratedForms[0].path).toBe('form2'); + expect(migratedForms[1].path).toBe('form3'); }); - describe("When searchFilters are provided", () => { + describe('When searchFilters are provided', () => { let log; let migratedForms; beforeEach(async () => { const migrated = await migrateForms( - { key__contains: "componentWithSimpleConditional" }, + { key__contains: 'componentWithSimpleConditional' }, {}, { disabled: true }, [ @@ -150,23 +150,23 @@ describe("Migration scripts", () => { log = migrated.log; }); - it("only returns search results for forms with components that matches both", async () => { - expect(Object.keys(log)).toEqual(["formWithSimpleConditionalToRadio", "formWithSimpleConditionalToCheckbox"]); + it('only returns search results for forms with components that matches both', async () => { + expect(Object.keys(log)).toEqual(['formWithSimpleConditionalToRadio', 'formWithSimpleConditionalToCheckbox']); }); - it("only migrates forms with components that matches both", async () => { + it('only migrates forms with components that matches both', async () => { expect(migratedForms).toEqual([ - expect.objectContaining({ path: "formWithSimpleConditionalToRadio" }), - expect.objectContaining({ path: "formWithSimpleConditionalToCheckbox" }), + expect.objectContaining({ path: 'formWithSimpleConditionalToRadio' }), + expect.objectContaining({ path: 'formWithSimpleConditionalToCheckbox' }), ]); }); }); - describe("When dependencyFilters are provided (but searchFilters are not)", () => { + describe('When dependencyFilters are provided (but searchFilters are not)', () => { let log; let migratedForms; beforeEach(async () => { - const migrated = await migrateForms({}, { type: "radio" }, { disabled: true }, [ + const migrated = await migrateForms({}, { type: 'radio' }, { disabled: true }, [ formWithSimpleConditionalToRadio, // match on dependencyFilters formWithAdvancedConditionalToRadio, // match on dependencyFilters formWithSimpleConditionalToCheckbox, // no match @@ -175,26 +175,26 @@ describe("Migration scripts", () => { migratedForms = migrated.migratedForms; }); - it("only returns search results for forms that matches filters", async () => { - expect(Object.keys(log)).toEqual(["formWithSimpleConditionalToRadio", "formWithAdvancedConditionalToRadio"]); + it('only returns search results for forms that matches filters', async () => { + expect(Object.keys(log)).toEqual(['formWithSimpleConditionalToRadio', 'formWithAdvancedConditionalToRadio']); }); - it("only migrates forms that matches filters", async () => { + it('only migrates forms that matches filters', async () => { expect(migratedForms).toEqual([ - expect.objectContaining({ path: "formWithSimpleConditionalToRadio" }), - expect.objectContaining({ path: "formWithAdvancedConditionalToRadio" }), + expect.objectContaining({ path: 'formWithSimpleConditionalToRadio' }), + expect.objectContaining({ path: 'formWithAdvancedConditionalToRadio' }), ]); }); }); - describe("When both searchFilters and dependencyFilters are provided", () => { + describe('When both searchFilters and dependencyFilters are provided', () => { let log; let migratedForms; beforeEach(async () => { const migrated = await migrateForms( - { key__contains: "componentWithSimpleConditional" }, - { type: "radio" }, + { key__contains: 'componentWithSimpleConditional' }, + { type: 'radio' }, { disabled: true }, [ formWithSimpleConditionalToRadio, // match on both search and dependency filters @@ -206,16 +206,16 @@ describe("Migration scripts", () => { log = migrated.log; }); - it("only returns search results for forms with components that matches both", async () => { - expect(Object.keys(log)).toEqual(["formWithSimpleConditionalToRadio"]); + it('only returns search results for forms with components that matches both', async () => { + expect(Object.keys(log)).toEqual(['formWithSimpleConditionalToRadio']); }); - it("only migrates forms with components that matches both", async () => { - expect(migratedForms).toEqual([expect.objectContaining({ path: "formWithSimpleConditionalToRadio" })]); + it('only migrates forms with components that matches both', async () => { + expect(migratedForms).toEqual([expect.objectContaining({ path: 'formWithSimpleConditionalToRadio' })]); }); }); - describe("When no filters are provided", () => { + describe('When no filters are provided', () => { let log; let migratedForms; @@ -229,79 +229,79 @@ describe("Migration scripts", () => { log = migrated.log; }); - it("returns search results for all forms", () => { + it('returns search results for all forms', () => { expect(Object.keys(log)).toEqual([ - "formWithSimpleConditionalToRadio", - "formWithAdvancedConditionalToRadio", - "formWithSimpleConditionalToCheckbox", + 'formWithSimpleConditionalToRadio', + 'formWithAdvancedConditionalToRadio', + 'formWithSimpleConditionalToCheckbox', ]); }); - it("migrates all forms", () => { + it('migrates all forms', () => { expect(migratedForms).toEqual([ - expect.objectContaining({ path: "formWithSimpleConditionalToRadio" }), - expect.objectContaining({ path: "formWithAdvancedConditionalToRadio" }), - expect.objectContaining({ path: "formWithSimpleConditionalToCheckbox" }), + expect.objectContaining({ path: 'formWithSimpleConditionalToRadio' }), + expect.objectContaining({ path: 'formWithAdvancedConditionalToRadio' }), + expect.objectContaining({ path: 'formWithSimpleConditionalToCheckbox' }), ]); }); }); }); - describe("getEditScript", () => { + describe('getEditScript', () => { let testComponent; beforeEach(() => { testComponent = { - prop1: "prop1", + prop1: 'prop1', prop2: { - prop2_1: "prop2_1", - prop2_2: "prop2_2", - prop2_3: "prop2_3", + prop2_1: 'prop2_1', + prop2_2: 'prop2_2', + prop2_3: 'prop2_3', }, prop3: { prop3_1: { - prop3_1_1: "prop3_1_1", - prop3_1_2: "prop3_1_2", + prop3_1_1: 'prop3_1_1', + prop3_1_2: 'prop3_1_2', }, prop3_2: { - prop3_2_1: "prop3_2_1", + prop3_2_1: 'prop3_2_1', }, - prop3_3: "prop3_3", + prop3_3: 'prop3_3', }, }; }); - it("returns the original component if editOptions is empty", () => { + it('returns the original component if editOptions is empty', () => { expect(getEditScript({})(testComponent)).toEqual(testComponent); }); - it("edits a property", () => { - const editOptions = { prop1: "newValue" }; - expect(getEditScript(editOptions)(testComponent)).toEqual({ ...testComponent, prop1: "newValue" }); + it('edits a property', () => { + const editOptions = { prop1: 'newValue' }; + expect(getEditScript(editOptions)(testComponent)).toEqual({ ...testComponent, prop1: 'newValue' }); }); - it("edits properties in nested property, while preserving existing properties", () => { - const editOptions = { "prop2.prop2_1": "newValue1", "prop2.prop2_2": "newValue2" }; + it('edits properties in nested property, while preserving existing properties', () => { + const editOptions = { 'prop2.prop2_1': 'newValue1', 'prop2.prop2_2': 'newValue2' }; expect(getEditScript(editOptions)(testComponent)).toEqual({ ...testComponent, - prop2: { ...testComponent.prop2, prop2_1: "newValue1", prop2_2: "newValue2" }, + prop2: { ...testComponent.prop2, prop2_1: 'newValue1', prop2_2: 'newValue2' }, }); }); - it("edits properties in several nested properties, while preserving existing properties", () => { + it('edits properties in several nested properties, while preserving existing properties', () => { const editOptions = { - prop1: "newValue1", - "prop2.prop2_2": "newValue2", - "prop3.prop3_1.prop3_1_1": "newValue3", - "prop3.prop3_3": "newValue4", + prop1: 'newValue1', + 'prop2.prop2_2': 'newValue2', + 'prop3.prop3_1.prop3_1_1': 'newValue3', + 'prop3.prop3_3': 'newValue4', }; expect(getEditScript(editOptions)(testComponent)).toEqual({ ...testComponent, - prop1: "newValue1", - prop2: { ...testComponent.prop2, prop2_2: "newValue2" }, + prop1: 'newValue1', + prop2: { ...testComponent.prop2, prop2_2: 'newValue2' }, prop3: { ...testComponent.prop3, - prop3_1: { ...testComponent.prop3.prop3_1, prop3_1_1: "newValue3" }, - prop3_3: "newValue4", + prop3_1: { ...testComponent.prop3.prop3_1, prop3_1_1: 'newValue3' }, + prop3_3: 'newValue4', }, }); }); diff --git a/packages/bygger-backend/src/migration/scripts/migrateSignatures.js b/packages/bygger-backend/src/migration/scripts/migrateSignatures.js index 07ef5844d..d7b8abf83 100644 --- a/packages/bygger-backend/src/migration/scripts/migrateSignatures.js +++ b/packages/bygger-backend/src/migration/scripts/migrateSignatures.js @@ -1,8 +1,8 @@ -import { generateDiff } from "../diffingTool"; +import { generateDiff } from '../diffingTool'; function createNewSignatures(form) { const { hasLabeledSignatures, signatures } = form.properties; - if (hasLabeledSignatures && signatures && signatures.signature1 !== "") { + if (hasLabeledSignatures && signatures && signatures.signature1 !== '') { return Object.keys(signatures) .filter((key) => key.match(/^signature\d$/)) .sort() @@ -23,8 +23,8 @@ function createNewSignatures(form) { } else { return [ { - label: "", - description: "", + label: '', + description: '', }, ]; } @@ -34,7 +34,7 @@ const migrateSignatures = (editOptions, affectedComponentsLogger = []) => (comp) => { const propertiesWithoutHasLabeledSignatures = Object.keys(comp.properties) - .filter((key) => key !== "hasLabeledSignatures") + .filter((key) => key !== 'hasLabeledSignatures') .flatMap((key) => ({ [key]: comp.properties[key] })); const editedComp = { ...comp, diff --git a/packages/bygger-backend/src/migration/scripts/migrateSignatures.test.js b/packages/bygger-backend/src/migration/scripts/migrateSignatures.test.js index cb5810030..1ff91126c 100644 --- a/packages/bygger-backend/src/migration/scripts/migrateSignatures.test.js +++ b/packages/bygger-backend/src/migration/scripts/migrateSignatures.test.js @@ -1,97 +1,97 @@ -import migrateSignatures from "./migrateSignatures"; +import migrateSignatures from './migrateSignatures'; const createMockForm = (signatures, hasLabeledSignatures) => ({ components: [], - display: "wizard", - name: "mockForm", - path: "mockForm", + display: 'wizard', + name: 'mockForm', + path: 'mockForm', properties: { - skjemanummer: "test-001", - tema: "xxx", + skjemanummer: 'test-001', + tema: 'xxx', signatures, hasLabeledSignatures, }, tags: [], - type: "form", - title: "Mock Form", + type: 'form', + title: 'Mock Form', }); -describe("Migration of signatures", () => { +describe('Migration of signatures', () => { let migrationScript; beforeAll(() => { migrationScript = migrateSignatures({}, []); }); - describe("for (legacy-)forms without a signatures object", () => { - it("adds an array of signatures with a default object with empty strings for label and description", () => { + describe('for (legacy-)forms without a signatures object', () => { + it('adds an array of signatures with a default object with empty strings for label and description', () => { const actual = migrationScript(createMockForm()); expect(actual.properties.signatures).toEqual([ { - label: "", - description: "", + label: '', + description: '', }, ]); }); }); - describe("for forms with existing custom signatures", () => { - it("changes the old signatures object to an array with one object for each signature in use", () => { + describe('for forms with existing custom signatures', () => { + it('changes the old signatures object to an array with one object for each signature in use', () => { const mockForm = createMockForm( { - signature1: "Signature 1", - signature2: "Signature 2", - signature3: "Signature 3", - signature4: "Signature 4", - signature5: "Signature 5", + signature1: 'Signature 1', + signature2: 'Signature 2', + signature3: 'Signature 3', + signature4: 'Signature 4', + signature5: 'Signature 5', }, true, ); const actual = migrationScript(mockForm); expect(actual.properties.signatures).toEqual([ - { label: "Signature 1" }, - { label: "Signature 2" }, - { label: "Signature 3" }, - { label: "Signature 4" }, - { label: "Signature 5" }, + { label: 'Signature 1' }, + { label: 'Signature 2' }, + { label: 'Signature 3' }, + { label: 'Signature 4' }, + { label: 'Signature 5' }, ]); }); - it("includes both label and description where both exist", () => { + it('includes both label and description where both exist', () => { const mockForm = createMockForm( { - signature1: "Signature 1", - signature1Description: "Signature 1 description", - signature2: "Signature 2", - signature2Description: "Signature 2 description", + signature1: 'Signature 1', + signature1Description: 'Signature 1 description', + signature2: 'Signature 2', + signature2Description: 'Signature 2 description', }, true, ); const actual = migrationScript(mockForm); expect(actual.properties.signatures).toEqual([ { - label: "Signature 1", - description: "Signature 1 description", + label: 'Signature 1', + description: 'Signature 1 description', }, { - label: "Signature 2", - description: "Signature 2 description", + label: 'Signature 2', + description: 'Signature 2 description', }, ]); }); - it("only adds a default object with empty strings for label and description where no signatures are used", () => { + it('only adds a default object with empty strings for label and description where no signatures are used', () => { const mockForm = createMockForm( - { signature1: "", signature2: "", signature3: "", signature4: "", signature5: "" }, + { signature1: '', signature2: '', signature3: '', signature4: '', signature5: '' }, true, ); const actual = migrationScript(mockForm); - expect(actual.properties.signatures).toEqual([{ label: "", description: "" }]); + expect(actual.properties.signatures).toEqual([{ label: '', description: '' }]); }); - it("removes the now unused hasLabeledSignatures boolean", () => { - const mockForm = createMockForm({ signature1: "" }, true); + it('removes the now unused hasLabeledSignatures boolean', () => { + const mockForm = createMockForm({ signature1: '' }, true); const actual = migrationScript(mockForm); - expect(actual.properties).not.toHaveProperty("hasLabeledSignatures"); + expect(actual.properties).not.toHaveProperty('hasLabeledSignatures'); }); }); }); diff --git a/packages/bygger-backend/src/migration/testData.ts b/packages/bygger-backend/src/migration/testData.ts index c9cc727c7..aadefd576 100644 --- a/packages/bygger-backend/src/migration/testData.ts +++ b/packages/bygger-backend/src/migration/testData.ts @@ -1,7 +1,7 @@ -import { Component, NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; +import { Component, NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; const originalPanelComponent = { - title: "Veiledning", + title: 'Veiledning', breadcrumbClickable: true, buttonSettings: { previous: true, @@ -12,174 +12,174 @@ const originalPanelComponent = { saveOnEnter: false, scrollToTop: false, collapsible: false, - key: "veiledning", - type: "panel", - label: "Veiledning", + key: 'veiledning', + type: 'panel', + label: 'Veiledning', input: false, components: [], tableView: false, }; const originalSkjemaGruppeComponent = { - legend: "Skjemagruppe", - key: "navSkjemagruppe", - type: "navSkjemagruppe", - label: "Skjemagruppe", + legend: 'Skjemagruppe', + key: 'navSkjemagruppe', + type: 'navSkjemagruppe', + label: 'Skjemagruppe', input: false, tableView: false, components: [], }; const originalTextFieldComponent = { - label: "Fornavn", - fieldSize: "input--xxl", - autocomplete: "given-name", - validateOn: "blur", + label: 'Fornavn', + fieldSize: 'input--xxl', + autocomplete: 'given-name', + validateOn: 'blur', validate: { required: true, }, - key: "nyttFornavn", - type: "textfield", + key: 'nyttFornavn', + type: 'textfield', input: true, dataGridLabel: true, tableView: true, } as unknown as Component; const originalFodselsnummerComponent = { - label: "Fødselsnummer / D-nummer", - key: "fodselsnummerDNummer", - type: "fnrfield", - fieldSize: "input--s", + label: 'Fødselsnummer / D-nummer', + key: 'fodselsnummerDNummer', + type: 'fnrfield', + fieldSize: 'input--s', input: true, spellcheck: false, dataGridLabel: true, - validateOn: "blur", + validateOn: 'blur', validate: { - custom: "valid = instance.originalValidateFnr(input)", + custom: 'valid = instance.originalValidateFnr(input)', required: true, }, tableView: true, }; const originalForm = { - path: "test-form", + path: 'test-form', components: [originalFodselsnummerComponent, originalTextFieldComponent], }; const radioComponent = { - key: "radioComponent", - id: "radioComponent", - label: "Radio", - type: "radio", + key: 'radioComponent', + id: 'radioComponent', + label: 'Radio', + type: 'radio', values: [ { - value: "ja", - label: "Ja", + value: 'ja', + label: 'Ja', }, { - value: "nei", - label: "Nei", + value: 'nei', + label: 'Nei', }, ], } as unknown as Component; const checkboxComponent = { - key: "checkboxComponent", - id: "checkboxComponent", - type: "checkbox", - label: "Checkbox", + key: 'checkboxComponent', + id: 'checkboxComponent', + type: 'checkbox', + label: 'Checkbox', }; const componentWithSimpleConditionalToRadio = { - key: "componentWithSimpleConditionalToRadio", - id: "componentWithSimpleConditionalToRadio", - label: "Component with simple conditional to radio", + key: 'componentWithSimpleConditionalToRadio', + id: 'componentWithSimpleConditionalToRadio', + label: 'Component with simple conditional to radio', conditional: { show: true, - when: "radioComponent", - eq: "ja", + when: 'radioComponent', + eq: 'ja', }, } as unknown as Component; const componentWithAdvancedConditionalToRadio = { - key: "componentWithAdvancedConditionalToRadio", - id: "componentWithAdvancedConditionalToRadio", - label: "Component with advanced conditional to radio", + key: 'componentWithAdvancedConditionalToRadio', + id: 'componentWithAdvancedConditionalToRadio', + label: 'Component with advanced conditional to radio', customConditional: 'show = data.radioComponent === "ja"', conditional: { show: true, - when: "radioComponent", - eq: "ja", + when: 'radioComponent', + eq: 'ja', }, } as unknown as Component; const componentWithSimpleConditionalToCheckbox = { - key: "componentWithSimpleConditionalToCheckbox", - id: "componentWithSimpleConditionalToCheckbox", - label: "Component with simple conditional to checkbox", + key: 'componentWithSimpleConditionalToCheckbox', + id: 'componentWithSimpleConditionalToCheckbox', + label: 'Component with simple conditional to checkbox', conditional: { show: true, - when: "checkboxComponent", + when: 'checkboxComponent', eq: true, }, }; const generalProperties = { - modified: "2022-11-17T13:12:38.825Z", - modifiedBy: "user@company.com", - published: "2022-11-17T13:12:38.825Z", - publishedBy: "publisher@company.com", - unpublished: "2022-12-24T17:00:00.825Z", - unpublishedBy: "user@company.com", + modified: '2022-11-17T13:12:38.825Z', + modifiedBy: 'user@company.com', + published: '2022-11-17T13:12:38.825Z', + publishedBy: 'publisher@company.com', + unpublished: '2022-12-24T17:00:00.825Z', + unpublishedBy: 'user@company.com', isTestForm: false, - publishedLanguages: ["en"], + publishedLanguages: ['en'], }; const formWithSimpleConditionalToRadio = { - name: "formWithSimpleConditionalToRadio", - path: "formWithSimpleConditionalToRadio", - title: "Form with simple conditional to radio", + name: 'formWithSimpleConditionalToRadio', + path: 'formWithSimpleConditionalToRadio', + title: 'Form with simple conditional to radio', properties: { - skjemanummer: "formWithSimpleConditionalToRadio", + skjemanummer: 'formWithSimpleConditionalToRadio', ...generalProperties, }, components: [radioComponent, componentWithSimpleConditionalToRadio], } as NavFormType; const formWithAdvancedConditionalToRadio = { - name: "formWithAdvancedConditionalToRadio", - path: "formWithAdvancedConditionalToRadio", - title: "Form with advanced conditional to radio", + name: 'formWithAdvancedConditionalToRadio', + path: 'formWithAdvancedConditionalToRadio', + title: 'Form with advanced conditional to radio', properties: { - skjemanummer: "formWithAdvancedConditionalToRadio", + skjemanummer: 'formWithAdvancedConditionalToRadio', ...generalProperties, }, components: [radioComponent, componentWithAdvancedConditionalToRadio], } as NavFormType; const formWithSimpleConditionalToCheckbox = { - name: "formWithSimpleConditionalToCheckbox", - path: "formWithSimpleConditionalToCheckbox", - title: "Form with simple conditional to checkbox", + name: 'formWithSimpleConditionalToCheckbox', + path: 'formWithSimpleConditionalToCheckbox', + title: 'Form with simple conditional to checkbox', properties: { - skjemanummer: "formWithSimpleConditionalToCheckbox", + skjemanummer: 'formWithSimpleConditionalToCheckbox', ...generalProperties, }, components: [checkboxComponent, componentWithSimpleConditionalToCheckbox], } as NavFormType; export { - originalTextFieldComponent, - originalSkjemaGruppeComponent, - originalFodselsnummerComponent, - originalPanelComponent, - originalForm, - radioComponent, checkboxComponent, - componentWithSimpleConditionalToRadio, componentWithAdvancedConditionalToRadio, componentWithSimpleConditionalToCheckbox, - formWithSimpleConditionalToRadio, + componentWithSimpleConditionalToRadio, formWithAdvancedConditionalToRadio, formWithSimpleConditionalToCheckbox, + formWithSimpleConditionalToRadio, + originalFodselsnummerComponent, + originalForm, + originalPanelComponent, + originalSkjemaGruppeComponent, + originalTextFieldComponent, + radioComponent, }; diff --git a/packages/bygger-backend/src/repoUtils.js b/packages/bygger-backend/src/repoUtils.js index b8fc3fba3..f90d16fcc 100644 --- a/packages/bygger-backend/src/repoUtils.js +++ b/packages/bygger-backend/src/repoUtils.js @@ -1,8 +1,8 @@ -import { stringTobase64 } from "./fetchUtils"; -import { logger } from "./logging/logger"; +import { stringTobase64 } from './fetchUtils'; +import { logger } from './logging/logger'; function areEqualWithoutWhiteSpaces(string1, string2) { - return string1.replace(/\s/g, "") === string2.replace(/\s/g, ""); + return string1.replace(/\s/g, '') === string2.replace(/\s/g, ''); } async function pushFileToRepo(repo, branch, path, message, fileContentAsBase64) { @@ -33,7 +33,7 @@ export function pushFilesAndUpdateMonorepoRefCallback(files, newMonorepoGitSha) const initialRef = await repo.getRef(branch); logger.info(`Perform ${files.length} change(s) on ${branch}, ref: ${initialRef}`); for (const file of files) { - logger.debug("Push file to repo", { branch, path: file.path, type: file.type, name: file.name }); + logger.debug('Push file to repo', { branch, path: file.path, type: file.type, name: file.name }); await pushFileToRepo( repo, branch, @@ -44,11 +44,11 @@ export function pushFilesAndUpdateMonorepoRefCallback(files, newMonorepoGitSha) } if (await repo.hasBranchChanged(initialRef, branch)) { - logger.info("Update monorepo ref", { newGitSha: newMonorepoGitSha, original: initialRef, branch }); + logger.info('Update monorepo ref', { newGitSha: newMonorepoGitSha, original: initialRef, branch }); await pushFileToRepo( repo, branch, - "MONOREPO", + 'MONOREPO', `oppdater monorepo ref: ${newMonorepoGitSha}`, stringTobase64(newMonorepoGitSha), ); @@ -83,8 +83,8 @@ export async function performChangesOnSeparateBranch(repo, base, branch, perform let updatedBaseSha; if (await repo.hasBranchChanged(baseRef, branch)) { // Only create and merge pull request if the branch contains changes, compared to the base branch - const pullRequest = await repo.createPullRequest("Automatic publishing job", branch, base); - logger.info("Created pull-request", { + const pullRequest = await repo.createPullRequest('Automatic publishing job', branch, base); + logger.info('Created pull-request', { pullRequest: pullRequest.data.number, baseRef, branch, @@ -93,7 +93,7 @@ export async function performChangesOnSeparateBranch(repo, base, branch, perform await repo.mergePullRequest(pullRequest.data.number, mergeCommitMessage); const updatedBase = await repo.getRef(base); updatedBaseSha = updatedBase.data.object.sha; - logger.info("Merged pull-request", { + logger.info('Merged pull-request', { updatedBaseSha, pullRequest: pullRequest.data.number, baseRef, diff --git a/packages/bygger-backend/src/routers/api/config.ts b/packages/bygger-backend/src/routers/api/config.ts index a8830571e..248e4fe64 100644 --- a/packages/bygger-backend/src/routers/api/config.ts +++ b/packages/bygger-backend/src/routers/api/config.ts @@ -1,12 +1,12 @@ -import { Response } from "express"; -import appConfig from "../../config"; -import { createFormioJwt } from "../../middleware/authHandler"; -import { ByggerRequest } from "../../types"; +import { Response } from 'express'; +import appConfig from '../../config'; +import { createFormioJwt } from '../../middleware/authHandler'; +import { ByggerRequest } from '../../types'; const config = (req: ByggerRequest, res: Response) => { const user = appConfig.isDevelopment ? undefined : req.getUser?.(); if (user) { - res.header("Bygger-Formio-Token", createFormioJwt(user)); + res.header('Bygger-Formio-Token', createFormioJwt(user)); } res.json({ formioProjectUrl: appConfig.formio.projectUrl, diff --git a/packages/bygger-backend/src/routers/api/deprecated-publish-bulk.ts b/packages/bygger-backend/src/routers/api/deprecated-publish-bulk.ts index a9d90a8fd..9bffe4077 100644 --- a/packages/bygger-backend/src/routers/api/deprecated-publish-bulk.ts +++ b/packages/bygger-backend/src/routers/api/deprecated-publish-bulk.ts @@ -1,9 +1,9 @@ -import { NextFunction, Request, Response } from "express"; -import { backendInstance } from "../../services"; +import { NextFunction, Request, Response } from 'express'; +import { backendInstance } from '../../services'; const deprecatedPublishBulk = async (req: Request, res: Response, next: NextFunction) => { if (!Array.isArray(req.body.payload.formPaths) || req.body.payload.formPaths.length === 0) { - res.status(400).send("Request is missing formPaths"); + res.status(400).send('Request is missing formPaths'); } try { const result = await backendInstance.bulkPublishForms(req.body.payload.formPaths); diff --git a/packages/bygger-backend/src/routers/api/deprecated-publish-form.ts b/packages/bygger-backend/src/routers/api/deprecated-publish-form.ts index eab396fe1..5999a49a3 100644 --- a/packages/bygger-backend/src/routers/api/deprecated-publish-form.ts +++ b/packages/bygger-backend/src/routers/api/deprecated-publish-form.ts @@ -1,5 +1,5 @@ -import { NextFunction, Request, Response } from "express"; -import { backendInstance } from "../../services"; +import { NextFunction, Request, Response } from 'express'; +import { backendInstance } from '../../services'; const deprecatedPublishForm = async (req: Request, res: Response, next: NextFunction) => { try { diff --git a/packages/bygger-backend/src/routers/api/deprecated-unpublish-form.ts b/packages/bygger-backend/src/routers/api/deprecated-unpublish-form.ts index faa7978a5..967001500 100644 --- a/packages/bygger-backend/src/routers/api/deprecated-unpublish-form.ts +++ b/packages/bygger-backend/src/routers/api/deprecated-unpublish-form.ts @@ -1,5 +1,5 @@ -import { NextFunction, Request, Response } from "express"; -import { backendInstance } from "../../services"; +import { NextFunction, Request, Response } from 'express'; +import { backendInstance } from '../../services'; const deprecatedUnpublishForm = async (req: Request, res: Response, next: NextFunction) => { try { diff --git a/packages/bygger-backend/src/routers/api/enhetsliste.ts b/packages/bygger-backend/src/routers/api/enhetsliste.ts index 48df08e7a..7675162b9 100644 --- a/packages/bygger-backend/src/routers/api/enhetsliste.ts +++ b/packages/bygger-backend/src/routers/api/enhetsliste.ts @@ -1,5 +1,5 @@ -import { NextFunction, Request, Response } from "express"; -import { backendInstance } from "../../services"; +import { NextFunction, Request, Response } from 'express'; +import { backendInstance } from '../../services'; const enhetsliste = async (req: Request, res: Response, next: NextFunction) => { try { diff --git a/packages/bygger-backend/src/routers/api/formDiff.ts b/packages/bygger-backend/src/routers/api/formDiff.ts index 53f0aa297..6cbc9ed56 100644 --- a/packages/bygger-backend/src/routers/api/formDiff.ts +++ b/packages/bygger-backend/src/routers/api/formDiff.ts @@ -1,7 +1,7 @@ -import { formDiffingTool } from "@navikt/skjemadigitalisering-shared-domain"; -import { NextFunction, Request, Response } from "express"; -import { backendInstance, formioService } from "../../services"; -import { NotFoundError } from "./helpers/errors"; +import { formDiffingTool } from '@navikt/skjemadigitalisering-shared-domain'; +import { NextFunction, Request, Response } from 'express'; +import { backendInstance, formioService } from '../../services'; +import { NotFoundError } from './helpers/errors'; const formDiff = async (req: Request, res: Response, next: NextFunction) => { try { @@ -26,7 +26,7 @@ const formDiff = async (req: Request, res: Response, next: NextFunction) => { }; const notFound = (next: NextFunction) => { - return next(new NotFoundError("Published form not found")); + return next(new NotFoundError('Published form not found')); }; export default formDiff; diff --git a/packages/bygger-backend/src/routers/api/helpers/apiErrorHandler.ts b/packages/bygger-backend/src/routers/api/helpers/apiErrorHandler.ts index 13b8381fb..78b534074 100644 --- a/packages/bygger-backend/src/routers/api/helpers/apiErrorHandler.ts +++ b/packages/bygger-backend/src/routers/api/helpers/apiErrorHandler.ts @@ -1,21 +1,21 @@ -import { NextFunction, Request, Response } from "express"; -import { HttpError as OldHttpError } from "../../../fetchUtils"; -import { logger } from "../../../logging/logger"; -import { ApiError, HttpError } from "./errors"; +import { NextFunction, Request, Response } from 'express'; +import { HttpError as OldHttpError } from '../../../fetchUtils'; +import { logger } from '../../../logging/logger'; +import { ApiError, HttpError } from './errors'; -const apiErrorHandler = (error: Error, req: Request, res: Response, next: NextFunction) => { +const apiErrorHandler = (error: Error, req: Request, res: Response, _next: NextFunction) => { if (error instanceof HttpError) { logger.error(`HttpError: ${error.message} (${error.status})`); res.sendStatus(error.status); } else if (error instanceof OldHttpError && error.response.status === 401) { - logger.warn("Unauthorized", error.message); - res.status(401).send("Unauthorized"); + logger.warn('Unauthorized', error.message); + res.status(401).send('Unauthorized'); } else if (error instanceof ApiError) { logger.error(error); - res.contentType("application/json"); + res.contentType('application/json'); res.status(500).send({ message: error.message, functional: error.functional }); } else { - logger.error("Internal server error:", error); + logger.error('Internal server error:', error); res.status(500).send(`Noe galt skjedde: ${error.message}`); } }; diff --git a/packages/bygger-backend/src/routers/api/helpers/authorizedPublisher.test.ts b/packages/bygger-backend/src/routers/api/helpers/authorizedPublisher.test.ts index 7d50dad36..effed824c 100644 --- a/packages/bygger-backend/src/routers/api/helpers/authorizedPublisher.test.ts +++ b/packages/bygger-backend/src/routers/api/helpers/authorizedPublisher.test.ts @@ -1,24 +1,24 @@ -import nock from "nock"; -import config from "../../../config"; -import { mockRequest, mockResponse } from "../../../test/testHelpers"; -import authorizedPublisher from "./authorizedPublisher"; +import nock from 'nock'; +import config from '../../../config'; +import { mockRequest, mockResponse } from '../../../test/testHelpers'; +import authorizedPublisher from './authorizedPublisher'; -describe("authorizedPublisher", () => { +describe('authorizedPublisher', () => { const projectUrl = config.formio.projectUrl; beforeAll(() => { - vi.spyOn(console, "error").mockImplementation(() => {}); + vi.spyOn(console, 'error').mockImplementation(() => {}); }); afterAll(() => { vi.restoreAllMocks(); }); - it("Accepts formio token in body", async () => { - nock(projectUrl).get("/current").reply(204); + it('Accepts formio token in body', async () => { + nock(projectUrl).get('/current').reply(204); const req = mockRequest({ body: { - token: "valid-formio-token", + token: 'valid-formio-token', }, }); const res = mockResponse(); @@ -28,14 +28,14 @@ describe("authorizedPublisher", () => { expect(next.mock.calls[0][0]).toBeUndefined(); }); - it("Accepts formio token in header", async () => { - nock(projectUrl).get("/current").reply(204); + it('Accepts formio token in header', async () => { + nock(projectUrl).get('/current').reply(204); const req = mockRequest({ headers: { - "Bygger-Formio-Token": "valid-formio-token", + 'Bygger-Formio-Token': 'valid-formio-token', }, body: { - foo: "bar", + foo: 'bar', }, }); const res = mockResponse(); @@ -45,7 +45,7 @@ describe("authorizedPublisher", () => { expect(next.mock.calls[0][0]).toBeUndefined(); }); - it("Rejects request when formio token is missing", async () => { + it('Rejects request when formio token is missing', async () => { const req = mockRequest({ body: { token: undefined, @@ -57,14 +57,14 @@ describe("authorizedPublisher", () => { expect(next).toHaveBeenCalledTimes(1); const nextArg = next.mock.calls[0][0]; expect(nextArg).toBeDefined(); - expect(nextArg.message).toEqual("Missing formio token"); + expect(nextArg.message).toBe('Missing formio token'); }); - it("Rejects request when formio token is invalid", async () => { - nock(projectUrl).get("/current").reply(401); + it('Rejects request when formio token is invalid', async () => { + nock(projectUrl).get('/current').reply(401); const req = mockRequest({ body: { - token: "invalid-formio-token", + token: 'invalid-formio-token', }, }); const res = mockResponse(); @@ -73,6 +73,6 @@ describe("authorizedPublisher", () => { expect(next).toHaveBeenCalledTimes(1); const nextArg = next.mock.calls[0][0]; expect(nextArg).toBeDefined(); - expect(nextArg.message).toEqual("Invalid formio token"); + expect(nextArg.message).toBe('Invalid formio token'); }); }); diff --git a/packages/bygger-backend/src/routers/api/helpers/authorizedPublisher.ts b/packages/bygger-backend/src/routers/api/helpers/authorizedPublisher.ts index b5c8773fb..5f9a59d5b 100644 --- a/packages/bygger-backend/src/routers/api/helpers/authorizedPublisher.ts +++ b/packages/bygger-backend/src/routers/api/helpers/authorizedPublisher.ts @@ -1,19 +1,19 @@ -import { NextFunction, Response } from "express"; -import { formioService } from "../../../services"; -import { ByggerRequest } from "../../../types"; -import { getFormioToken } from "../../../util/requestTool"; -import { UnauthorizedError } from "./errors"; +import { NextFunction, Response } from 'express'; +import { formioService } from '../../../services'; +import { ByggerRequest } from '../../../types'; +import { getFormioToken } from '../../../util/requestTool'; +import { UnauthorizedError } from './errors'; const authorizedPublisher = async (req: ByggerRequest, res: Response, next: NextFunction) => { const formioToken = getFormioToken(req); if (!formioToken) { - next(new UnauthorizedError("Missing formio token")); + next(new UnauthorizedError('Missing formio token')); return; } try { await formioService.getFormioUser(formioToken); } catch (e) { - next(new UnauthorizedError("Invalid formio token")); + next(new UnauthorizedError('Invalid formio token')); return; } req.getFormioToken = () => formioToken; diff --git a/packages/bygger-backend/src/routers/api/helpers/errors.ts b/packages/bygger-backend/src/routers/api/helpers/errors.ts index 84b287762..01c08259e 100644 --- a/packages/bygger-backend/src/routers/api/helpers/errors.ts +++ b/packages/bygger-backend/src/routers/api/helpers/errors.ts @@ -38,6 +38,6 @@ export class ApiError extends Error { super(message); this.functional = functional; this.cause = cause; - this.name = "ApiError"; + this.name = 'ApiError'; } } diff --git a/packages/bygger-backend/src/routers/api/index.ts b/packages/bygger-backend/src/routers/api/index.ts index 3cbed2068..a61f2853d 100644 --- a/packages/bygger-backend/src/routers/api/index.ts +++ b/packages/bygger-backend/src/routers/api/index.ts @@ -1,41 +1,41 @@ -import express from "express"; -import config from "./config"; -import deprecatedPublishBulk from "./deprecated-publish-bulk"; -import deprecatedPublishForm from "./deprecated-publish-form"; -import deprecatedUnpublishForm from "./deprecated-unpublish-form"; -import enhetsliste from "./enhetsliste"; -import formDiff from "./formDiff"; -import apiErrorHandler from "./helpers/apiErrorHandler"; -import authorizedPublisher from "./helpers/authorizedPublisher"; -import migrate from "./migrate"; -import migratePreview from "./migrate-preview"; -import migrateUpdate from "./migrate-update"; -import publishForm from "./publish-form"; -import publishForms from "./publish-forms"; -import publishResource from "./publish-resource"; -import publishedForms from "./published-forms"; -import reportsRouter from "./reports"; -import temakoder from "./temakoder"; -import unpublishForm from "./unpublish-form"; +import express from 'express'; +import config from './config'; +import deprecatedPublishBulk from './deprecated-publish-bulk'; +import deprecatedPublishForm from './deprecated-publish-form'; +import deprecatedUnpublishForm from './deprecated-unpublish-form'; +import enhetsliste from './enhetsliste'; +import formDiff from './formDiff'; +import apiErrorHandler from './helpers/apiErrorHandler'; +import authorizedPublisher from './helpers/authorizedPublisher'; +import migrate from './migrate'; +import migratePreview from './migrate-preview'; +import migrateUpdate from './migrate-update'; +import publishForm from './publish-form'; +import publishForms from './publish-forms'; +import publishResource from './publish-resource'; +import publishedForms from './published-forms'; +import reportsRouter from './reports'; +import temakoder from './temakoder'; +import unpublishForm from './unpublish-form'; const apiRouter = express.Router(); -apiRouter.get("/config", config); -apiRouter.put("/publish/:formPath", authorizedPublisher, deprecatedPublishForm); -apiRouter.delete("/publish/:formPath", authorizedPublisher, deprecatedUnpublishForm); -apiRouter.put("/published-forms/:formPath", authorizedPublisher, publishForm); -apiRouter.get("/published-forms/:formPath", publishedForms.get); -apiRouter.delete("/published-forms/:formPath", authorizedPublisher, unpublishForm); -apiRouter.post("/published-forms", authorizedPublisher, publishForms); -apiRouter.post("/publish-bulk", authorizedPublisher, deprecatedPublishBulk); -apiRouter.put("/published-resource/:resourceName", authorizedPublisher, publishResource); -apiRouter.get("/enhetsliste", enhetsliste); -apiRouter.get("/temakoder", temakoder); -apiRouter.use("/reports", reportsRouter); -apiRouter.get("/migrate", migrate); -apiRouter.get("/migrate/preview/:formPath", migratePreview); -apiRouter.post("/migrate/update", authorizedPublisher, migrateUpdate); -apiRouter.get("/form/:formPath/diff", formDiff); +apiRouter.get('/config', config); +apiRouter.put('/publish/:formPath', authorizedPublisher, deprecatedPublishForm); +apiRouter.delete('/publish/:formPath', authorizedPublisher, deprecatedUnpublishForm); +apiRouter.put('/published-forms/:formPath', authorizedPublisher, publishForm); +apiRouter.get('/published-forms/:formPath', publishedForms.get); +apiRouter.delete('/published-forms/:formPath', authorizedPublisher, unpublishForm); +apiRouter.post('/published-forms', authorizedPublisher, publishForms); +apiRouter.post('/publish-bulk', authorizedPublisher, deprecatedPublishBulk); +apiRouter.put('/published-resource/:resourceName', authorizedPublisher, publishResource); +apiRouter.get('/enhetsliste', enhetsliste); +apiRouter.get('/temakoder', temakoder); +apiRouter.use('/reports', reportsRouter); +apiRouter.get('/migrate', migrate); +apiRouter.get('/migrate/preview/:formPath', migratePreview); +apiRouter.post('/migrate/update', authorizedPublisher, migrateUpdate); +apiRouter.get('/form/:formPath/diff', formDiff); apiRouter.use(apiErrorHandler); diff --git a/packages/bygger-backend/src/routers/api/migrate-preview.ts b/packages/bygger-backend/src/routers/api/migrate-preview.ts index f02008843..f7a34a4f8 100644 --- a/packages/bygger-backend/src/routers/api/migrate-preview.ts +++ b/packages/bygger-backend/src/routers/api/migrate-preview.ts @@ -1,11 +1,11 @@ -import { NextFunction, Request, Response } from "express"; -import { previewForm } from "../../migration/migrationScripts"; -import { formioService } from "../../services"; +import { NextFunction, Request, Response } from 'express'; +import { previewForm } from '../../migration/migrationScripts'; +import { formioService } from '../../services'; const migratePreview = async (req: Request, res: Response, next: NextFunction) => { - const searchFilters = JSON.parse((req.query["searchFilters"] as string) || "{}"); - const dependencyFilters = JSON.parse((req.query["dependencyFilters"] as string) || "{}"); - const editOptions = JSON.parse((req.query["editOptions"] as string) || "{}"); + const searchFilters = JSON.parse((req.query['searchFilters'] as string) || '{}'); + const dependencyFilters = JSON.parse((req.query['dependencyFilters'] as string) || '{}'); + const editOptions = JSON.parse((req.query['editOptions'] as string) || '{}'); try { const { formPath } = req.params; const form = await formioService.getForm(formPath); diff --git a/packages/bygger-backend/src/routers/api/migrate-update.ts b/packages/bygger-backend/src/routers/api/migrate-update.ts index fa72bedf1..734bf788f 100644 --- a/packages/bygger-backend/src/routers/api/migrate-update.ts +++ b/packages/bygger-backend/src/routers/api/migrate-update.ts @@ -1,12 +1,12 @@ -import { NextFunction, Response } from "express"; -import { migrateForms } from "../../migration/migrationScripts"; -import { formioService } from "../../services"; -import { ByggerRequest } from "../../types"; +import { NextFunction, Response } from 'express'; +import { migrateForms } from '../../migration/migrationScripts'; +import { formioService } from '../../services'; +import { ByggerRequest } from '../../types'; const migrateUpdate = async (req: ByggerRequest, res: Response, next: NextFunction) => { const { searchFilters, dependencyFilters, editOptions, include } = req.body.payload; - const formioToken = req.getFormioToken?.()!; - const userName = req.getUser?.().name!; + const formioToken = req.getFormioToken?.(); + const userName = req.getUser?.().name; try { const allForms = await formioService.getAllForms(); const { migratedForms } = await migrateForms(searchFilters, dependencyFilters, editOptions, allForms, include); diff --git a/packages/bygger-backend/src/routers/api/migrate.ts b/packages/bygger-backend/src/routers/api/migrate.ts index a3d31dfe0..ef7aeb87b 100644 --- a/packages/bygger-backend/src/routers/api/migrate.ts +++ b/packages/bygger-backend/src/routers/api/migrate.ts @@ -1,14 +1,14 @@ -import { NextFunction, Request, Response } from "express"; -import { migrateForms } from "../../migration/migrationScripts"; -import { formioService } from "../../services"; +import { NextFunction, Request, Response } from 'express'; +import { migrateForms } from '../../migration/migrationScripts'; +import { formioService } from '../../services'; const migrate = async (req: Request, res: Response, next: NextFunction) => { - const searchFilters = JSON.parse((req.query["searchFilters"] as string) || "{}"); - const dependencyFilters = JSON.parse((req.query["dependencyFilters"] as string) || "{}"); - const editOptions = JSON.parse((req.query["editOptions"] as string) || "{}"); + const searchFilters = JSON.parse((req.query['searchFilters'] as string) || '{}'); + const dependencyFilters = JSON.parse((req.query['dependencyFilters'] as string) || '{}'); + const editOptions = JSON.parse((req.query['editOptions'] as string) || '{}'); try { if (Object.keys({ ...searchFilters, ...dependencyFilters }).length === 0) - throw new Error("Migreringen mangler søkefiltre"); + throw new Error('Migreringen mangler søkefiltre'); const allForms = await formioService.getAllForms(); const { log } = await migrateForms(searchFilters, dependencyFilters, editOptions, allForms); res.send(log); diff --git a/packages/bygger-backend/src/routers/api/publish-form.ts b/packages/bygger-backend/src/routers/api/publish-form.ts index 07b2ce151..2bbb67936 100644 --- a/packages/bygger-backend/src/routers/api/publish-form.ts +++ b/packages/bygger-backend/src/routers/api/publish-form.ts @@ -1,7 +1,7 @@ -import { NextFunction, Request, Response } from "express"; -import { logger } from "../../logging/logger"; -import { publisherService } from "../../services"; -import { BadRequest } from "./helpers/errors"; +import { NextFunction, Request, Response } from 'express'; +import { logger } from '../../logging/logger'; +import { publisherService } from '../../services'; +import { BadRequest } from './helpers/errors'; const publishForm = async (req: Request, res: Response, next: NextFunction) => { const formioToken = req.getFormioToken(); @@ -10,19 +10,19 @@ const publishForm = async (req: Request, res: Response, next: NextFunction) => { const { form, translations } = req.body; if (formPath !== form.path) { - next(new BadRequest("Path mismatch attempting to publish form")); + next(new BadRequest('Path mismatch attempting to publish form')); return; } const logMeta = { formPath, userName }; - logger.info("Attempting to publish form", logMeta); + logger.info('Attempting to publish form', logMeta); try { const result = await publisherService.publishForm(form, translations, { formioToken, userName }); - logger.info("Form is published", logMeta); + logger.info('Form is published', logMeta); res.json(result); } catch (error) { - logger.error("Failed to publish form", logMeta); + logger.error('Failed to publish form', logMeta); next(error); } }; diff --git a/packages/bygger-backend/src/routers/api/publish-forms.ts b/packages/bygger-backend/src/routers/api/publish-forms.ts index c23fcd8a7..4bf3ca8b9 100644 --- a/packages/bygger-backend/src/routers/api/publish-forms.ts +++ b/packages/bygger-backend/src/routers/api/publish-forms.ts @@ -1,7 +1,7 @@ -import { NextFunction, Request, Response } from "express"; -import { logger } from "../../logging/logger"; -import { formioService, publisherService } from "../../services"; -import { BadRequest } from "./helpers/errors"; +import { NextFunction, Request, Response } from 'express'; +import { logger } from '../../logging/logger'; +import { formioService, publisherService } from '../../services'; +import { BadRequest } from './helpers/errors'; const publishForms = async (req: Request, res: Response, next: NextFunction) => { const formioToken = req.getFormioToken(); @@ -9,19 +9,19 @@ const publishForms = async (req: Request, res: Response, next: NextFunction) => const { formPaths } = req.body.payload; if (!Array.isArray(formPaths) || formPaths.length === 0) { - next(new BadRequest("Request is missing formPaths")); + next(new BadRequest('Request is missing formPaths')); return; } const logMeta = { formPaths, userName }; - logger.info("Attempting to publish forms", logMeta); + logger.info('Attempting to publish forms', logMeta); try { const forms: any = await formioService.getForms(formPaths); const gitSha = await publisherService.publishForms(forms, { formioToken, userName }); - logger.info("Forms are published", logMeta); + logger.info('Forms are published', logMeta); res.json({ changed: !!gitSha, gitSha }); } catch (error) { - logger.error("Failed to publish forms", logMeta); + logger.error('Failed to publish forms', logMeta); next(error); } }; diff --git a/packages/bygger-backend/src/routers/api/publish-resource.test.ts b/packages/bygger-backend/src/routers/api/publish-resource.test.ts index 5df7a7923..2ef120239 100644 --- a/packages/bygger-backend/src/routers/api/publish-resource.test.ts +++ b/packages/bygger-backend/src/routers/api/publish-resource.test.ts @@ -1,16 +1,16 @@ -import { mockRequest, mockResponse } from "../../test/testHelpers"; -import publishResource, { isValidResource } from "./publish-resource"; +import { mockRequest, mockResponse } from '../../test/testHelpers'; +import publishResource, { isValidResource } from './publish-resource'; -vi.mock("../../services/index.ts", () => { +vi.mock('../../services/index.ts', () => { return { backendInstance: { publishResource: vi.fn() } }; }); -describe("publish-resource", () => { - describe("PUT handler", () => { - it("accepts valid resource name", async () => { +describe('publish-resource', () => { + describe('PUT handler', () => { + it('accepts valid resource name', async () => { const req = mockRequest({ - params: { resourceName: "mottaksadresser" }, - body: { token: "test-token", resource: "{}" }, + params: { resourceName: 'mottaksadresser' }, + body: { token: 'test-token', resource: '{}' }, }); const res = mockResponse(); const next = vi.fn(); @@ -20,10 +20,10 @@ describe("publish-resource", () => { expect(res.json).toHaveBeenCalledTimes(1); }); - it("rejects invalid resource name", async () => { + it('rejects invalid resource name', async () => { const req = mockRequest({ - params: { resourceName: "random-resource-name" }, - body: { token: "test-token", resource: "{}" }, + params: { resourceName: 'random-resource-name' }, + body: { token: 'test-token', resource: '{}' }, }); const res = mockResponse(); const next = vi.fn(); @@ -34,30 +34,30 @@ describe("publish-resource", () => { }); }); - describe("isValidResource", () => { - it("mottaksadresser is valid", () => { - expect(isValidResource("mottaksadresser")).toBe(true); + describe('isValidResource', () => { + it('mottaksadresser is valid', () => { + expect(isValidResource('mottaksadresser')).toBe(true); }); - describe("global-translations", () => { - it("global-translations without language code is not valid", () => { - expect(isValidResource("global-translations")).toBe(false); + describe('global-translations', () => { + it('global-translations without language code is not valid', () => { + expect(isValidResource('global-translations')).toBe(false); }); - it("en is valid", () => { - expect(isValidResource("global-translations-en")).toBe(true); + it('en is valid', () => { + expect(isValidResource('global-translations-en')).toBe(true); }); - it("pl is valid", () => { - expect(isValidResource("global-translations-pl")).toBe(true); + it('pl is valid', () => { + expect(isValidResource('global-translations-pl')).toBe(true); }); - it("nn-NO is valid", () => { - expect(isValidResource("global-translations-nn-NO")).toBe(true); + it('nn-NO is valid', () => { + expect(isValidResource('global-translations-nn-NO')).toBe(true); }); - it("accepts only language codes as postfix", () => { - expect(isValidResource("global-translations-randomstring")).toBe(false); + it('accepts only language codes as postfix', () => { + expect(isValidResource('global-translations-randomstring')).toBe(false); }); }); }); diff --git a/packages/bygger-backend/src/routers/api/publish-resource.ts b/packages/bygger-backend/src/routers/api/publish-resource.ts index 590632600..e12c68042 100644 --- a/packages/bygger-backend/src/routers/api/publish-resource.ts +++ b/packages/bygger-backend/src/routers/api/publish-resource.ts @@ -1,6 +1,6 @@ -import { NextFunction, Request, Response } from "express"; -import { backendInstance } from "../../services"; -import { ApiError, BadRequest } from "./helpers/errors"; +import { NextFunction, Request, Response } from 'express'; +import { backendInstance } from '../../services'; +import { ApiError, BadRequest } from './helpers/errors'; const ALLOWED_RESOURCES = [/^mottaksadresser$/, /^global-translations-([a-z]{2}(-NO)?)$/]; export const isValidResource = (resourceName: string) => { @@ -17,7 +17,7 @@ const publishResource = async (req: Request, res: Response, next: NextFunction) const result = await backendInstance.publishResource(resourceName, req.body.resource); res.json({ changed: !!result, result }); } catch (error) { - next(new ApiError("Publisering feilet", true, error as Error)); + next(new ApiError('Publisering feilet', true, error as Error)); } }; diff --git a/packages/bygger-backend/src/routers/api/published-forms/index.ts b/packages/bygger-backend/src/routers/api/published-forms/index.ts index 4c86308b7..a9fc38a06 100644 --- a/packages/bygger-backend/src/routers/api/published-forms/index.ts +++ b/packages/bygger-backend/src/routers/api/published-forms/index.ts @@ -1,5 +1,5 @@ -import { NextFunction, Request, Response } from "express"; -import { backendInstance } from "../../../services"; +import { NextFunction, Request, Response } from 'express'; +import { backendInstance } from '../../../services'; const publishedForms = { get: async (req: Request, res: Response, next: NextFunction) => { diff --git a/packages/bygger-backend/src/routers/api/reports/index.ts b/packages/bygger-backend/src/routers/api/reports/index.ts index 7deb83175..ef4fdc48c 100644 --- a/packages/bygger-backend/src/routers/api/reports/index.ts +++ b/packages/bygger-backend/src/routers/api/reports/index.ts @@ -1,12 +1,12 @@ -import express from "express"; -import { adHandlers } from "../../../middleware/azureAd"; -import report from "./report"; -import reports from "./reports"; +import express from 'express'; +import { adHandlers } from '../../../middleware/azureAd'; +import report from './report'; +import reports from './reports'; const reportsRouter = express.Router(); -reportsRouter.all("*", adHandlers.isAdmin); -reportsRouter.get("/", reports); -reportsRouter.get("/:reportId", report); +reportsRouter.all('*', adHandlers.isAdmin); +reportsRouter.get('/', reports); +reportsRouter.get('/:reportId', report); export default reportsRouter; diff --git a/packages/bygger-backend/src/routers/api/reports/report.ts b/packages/bygger-backend/src/routers/api/reports/report.ts index 249380c15..3e843e9d0 100644 --- a/packages/bygger-backend/src/routers/api/reports/report.ts +++ b/packages/bygger-backend/src/routers/api/reports/report.ts @@ -1,6 +1,6 @@ -import { RequestHandler } from "express"; -import { reportService } from "../../../services"; -import { ApiError } from "../helpers/errors"; +import { RequestHandler } from 'express'; +import { reportService } from '../../../services'; +import { ApiError } from '../helpers/errors'; const report: RequestHandler = async (req, res, next) => { const { reportId } = req.params; @@ -13,7 +13,7 @@ const report: RequestHandler = async (req, res, next) => { res.attachment(`${reportId}.${report.fileEnding}`); await reportService.generate(reportId, res); } catch (err) { - next(new ApiError("Kunne ikke generere rapport", true, err as Error)); + next(new ApiError('Kunne ikke generere rapport', true, err as Error)); } }; diff --git a/packages/bygger-backend/src/routers/api/reports/reports.ts b/packages/bygger-backend/src/routers/api/reports/reports.ts index d1f266e3a..e03d6a26d 100644 --- a/packages/bygger-backend/src/routers/api/reports/reports.ts +++ b/packages/bygger-backend/src/routers/api/reports/reports.ts @@ -1,5 +1,5 @@ -import { RequestHandler } from "express"; -import { reportService } from "../../../services"; +import { RequestHandler } from 'express'; +import { reportService } from '../../../services'; const reports: RequestHandler = async (req, res) => { res.json(reportService.getAllReports()); diff --git a/packages/bygger-backend/src/routers/api/temakoder.ts b/packages/bygger-backend/src/routers/api/temakoder.ts index a6efb1cc0..6fb85d1cb 100644 --- a/packages/bygger-backend/src/routers/api/temakoder.ts +++ b/packages/bygger-backend/src/routers/api/temakoder.ts @@ -1,5 +1,5 @@ -import { NextFunction, Request, Response } from "express"; -import { backendInstance } from "../../services"; +import { NextFunction, Request, Response } from 'express'; +import { backendInstance } from '../../services'; const temakoder = async (req: Request, res: Response, next: NextFunction) => { try { diff --git a/packages/bygger-backend/src/routers/api/unpublish-form.ts b/packages/bygger-backend/src/routers/api/unpublish-form.ts index 753470317..ddeb72175 100644 --- a/packages/bygger-backend/src/routers/api/unpublish-form.ts +++ b/packages/bygger-backend/src/routers/api/unpublish-form.ts @@ -1,6 +1,6 @@ -import { NextFunction, Request, Response } from "express"; -import { logger } from "../../logging/logger"; -import { formioService, publisherService } from "../../services"; +import { NextFunction, Request, Response } from 'express'; +import { logger } from '../../logging/logger'; +import { formioService, publisherService } from '../../services'; const unpublishForm = async (req: Request, res: Response, next: NextFunction) => { const formioToken = req.getFormioToken(); @@ -8,15 +8,15 @@ const unpublishForm = async (req: Request, res: Response, next: NextFunction) => const { formPath } = req.params; const logMeta = { formPath, userName }; - logger.info("Attempting to unpublish form", logMeta); + logger.info('Attempting to unpublish form', logMeta); try { const form = await formioService.getForm(formPath); const result = await publisherService.unpublishForm(form, { formioToken, userName }); - logger.info("Form is unpublished", logMeta); + logger.info('Form is unpublished', logMeta); res.json(result); } catch (error) { - logger.error("Failed to unpublish form", logMeta); + logger.error('Failed to unpublish form', logMeta); next(error); } }; diff --git a/packages/bygger-backend/src/routers/internal/index.ts b/packages/bygger-backend/src/routers/internal/index.ts index 80d12b258..b30157777 100644 --- a/packages/bygger-backend/src/routers/internal/index.ts +++ b/packages/bygger-backend/src/routers/internal/index.ts @@ -1,8 +1,8 @@ -import express, { Request, Response } from "express"; +import express, { Request, Response } from 'express'; const internalRouter = express.Router(); -internalRouter.get("/isAlive", (req: Request, res: Response) => res.send("Alive")); -internalRouter.get("/isReady", (req: Request, res: Response) => res.send("Ready")); +internalRouter.get('/isAlive', (req: Request, res: Response) => res.send('Alive')); +internalRouter.get('/isReady', (req: Request, res: Response) => res.send('Ready')); export default internalRouter; diff --git a/packages/bygger-backend/src/routers/notifications/index.ts b/packages/bygger-backend/src/routers/notifications/index.ts index e8566347c..6afa9fc8d 100644 --- a/packages/bygger-backend/src/routers/notifications/index.ts +++ b/packages/bygger-backend/src/routers/notifications/index.ts @@ -1,11 +1,11 @@ -import express from "express"; -import authorizedPusher from "../../middleware/authorizedPusher"; -import apiErrorHandler from "../api/helpers/apiErrorHandler"; -import pusher from "./pusher"; +import express from 'express'; +import authorizedPusher from '../../middleware/authorizedPusher'; +import apiErrorHandler from '../api/helpers/apiErrorHandler'; +import pusher from './pusher'; const notificationsRouter = express.Router(); -notificationsRouter.post("/", authorizedPusher, pusher.post); +notificationsRouter.post('/', authorizedPusher, pusher.post); notificationsRouter.use(apiErrorHandler); export default notificationsRouter; diff --git a/packages/bygger-backend/src/routers/notifications/pusher.ts b/packages/bygger-backend/src/routers/notifications/pusher.ts index 356e0ae31..d33e98b5e 100644 --- a/packages/bygger-backend/src/routers/notifications/pusher.ts +++ b/packages/bygger-backend/src/routers/notifications/pusher.ts @@ -1,27 +1,27 @@ -import { PushEvent } from "@octokit/webhooks-types"; -import { NextFunction, Request, Response } from "express"; -import { logger } from "../../logging/logger"; -import { backendInstance, pusherService } from "../../services"; -import { PusherEvent } from "../../services/PusherService"; -import { toMeta } from "../../util/logUtils"; -import { ApiError } from "../api/helpers/errors"; +import { PushEvent } from '@octokit/webhooks-types'; +import { NextFunction, Request, Response } from 'express'; +import { logger } from '../../logging/logger'; +import { backendInstance, pusherService } from '../../services'; +import { PusherEvent } from '../../services/PusherService'; +import { toMeta } from '../../util/logUtils'; +import { ApiError } from '../api/helpers/errors'; interface NotificationRequestBody { - type: "success" | "failure"; + type: 'success' | 'failure'; githubEventMessage: PushEvent; } const pusher = { post: async (req: Request, res: Response, next: NextFunction) => { const body: NotificationRequestBody = req.body; - const logMeta = toMeta("requestBody", body); + const logMeta = toMeta('requestBody', body); try { - logger.info("Received notification", logMeta); + logger.info('Received notification', logMeta); const pusherEvent: PusherEvent = backendInstance.interpretGithubPushEvent(body.githubEventMessage, body.type); await pusherService.trigger(pusherEvent); } catch (error) { - logger.warn("Failed to process notification", { ...logMeta, error }); - return next(new ApiError("Failed to process notification", true, error as Error)); + logger.warn('Failed to process notification', { ...logMeta, error }); + return next(new ApiError('Failed to process notification', true, error as Error)); } return res.sendStatus(200); }, diff --git a/packages/bygger-backend/src/server.js b/packages/bygger-backend/src/server.js index cb41e17de..9f820e4c1 100644 --- a/packages/bygger-backend/src/server.js +++ b/packages/bygger-backend/src/server.js @@ -1,30 +1,27 @@ -import * as crypto from "crypto"; -import express from "express"; -import correlator from "express-correlation-id"; -import config from "./config"; -import { buildDirectory, buildDirectoryIndexHtml } from "./context.js"; -import authHandler from "./middleware/authHandler"; -import { fsAccessRateLimiter } from "./middleware/ratelimit"; -import apiRouter from "./routers/api"; -import internalRouter from "./routers/internal"; -import notificationsRouter from "./routers/notifications"; -import "./util/errorToJson"; - -global.crypto = crypto; +import express from 'express'; +import correlator from 'express-correlation-id'; +import config from './config'; +import { buildDirectory, buildDirectoryIndexHtml } from './context.js'; +import authHandler from './middleware/authHandler'; +import { fsAccessRateLimiter } from './middleware/ratelimit'; +import apiRouter from './routers/api'; +import internalRouter from './routers/internal'; +import notificationsRouter from './routers/notifications'; +import './util/errorToJson'; const app = express(); -app.use(express.json({ limit: "50mb" })); -app.use(express.urlencoded({ extended: true, limit: "50mb" })); +app.use(express.json({ limit: '50mb' })); +app.use(express.urlencoded({ extended: true, limit: '50mb' })); app.use(correlator()); -app.use("/internal", internalRouter); -app.use("/api", authHandler, apiRouter); -app.use("/notifications", notificationsRouter); +app.use('/internal', internalRouter); +app.use('/api', authHandler, apiRouter); +app.use('/notifications', notificationsRouter); if (import.meta.env.PROD) { // serve built app in production (served by vite in development) app.use(express.static(buildDirectory)); - app.get("/*", fsAccessRateLimiter, (req, res) => { + app.get('/*', fsAccessRateLimiter, (req, res) => { res.sendFile(buildDirectoryIndexHtml); }); } diff --git a/packages/bygger-backend/src/services/PublisherService.test.ts b/packages/bygger-backend/src/services/PublisherService.test.ts index de7a90b9e..2f739cd25 100644 --- a/packages/bygger-backend/src/services/PublisherService.test.ts +++ b/packages/bygger-backend/src/services/PublisherService.test.ts @@ -1,13 +1,13 @@ -import { FormPropertiesType, NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; -import nock from "nock"; -import { Backend } from "../Backend"; -import config from "../config"; -import PublisherService from "./PublisherService"; -import { formioService } from "./index"; +import { FormPropertiesType, NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; +import nock from 'nock'; +import { Backend } from '../Backend'; +import config from '../config'; +import PublisherService from './PublisherService'; +import { formioService } from './index'; -const opts = { userName: "todd", formioToken: "valid-formio-token" }; +const opts = { userName: 'todd', formioToken: 'valid-formio-token' }; -describe("PublisherService", () => { +describe('PublisherService', () => { let publisherService: PublisherService; let backendMock: Backend; @@ -17,13 +17,13 @@ describe("PublisherService", () => { nock.cleanAll(); }); - describe("publishForm", () => { - describe("when publishing succeeds", () => { - const testForm = { _id: "1", properties: {} } as NavFormType; + describe('publishForm', () => { + describe('when publishing succeeds', () => { + const testForm = { _id: '1', properties: {} } as NavFormType; let nockScope: nock.Scope; beforeEach(() => { - backendMock = { publishForm: () => "git-commit-hash" } as unknown as Backend; + backendMock = { publishForm: () => 'git-commit-hash' } as unknown as Backend; publisherService = new PublisherService(formioService, backendMock); nockScope = nock(config.formio.projectUrl) .put(/\/form\/(\d*)$/) @@ -35,19 +35,19 @@ describe("PublisherService", () => { expect(nockScope.isDone()).toBe(true); }); - it("adds properties modified and published", async () => { + it('adds properties modified and published', async () => { const translations = {}; const { changed, form } = await publisherService.publishForm(testForm, translations, opts); expect(changed).toBe(true); expect(form.properties.modified).toBeDefined(); - expect(form.properties.modifiedBy).toEqual("todd"); + expect(form.properties.modifiedBy).toBe('todd'); expect(form.properties.published).toBeDefined(); - expect(form.properties.publishedBy).toEqual("todd"); + expect(form.properties.publishedBy).toBe('todd'); }); - describe("property: publishedLanguages", () => { - it("adds publishedLanguages to properties", async () => { - const translations = { en: {}, "nn-NO": {} }; + describe('property: publishedLanguages', () => { + it('adds publishedLanguages to properties', async () => { + const translations = { en: {}, 'nn-NO': {} }; const testFormWithNoPublishedLanguages: NavFormType = { ...testForm, properties: { @@ -55,14 +55,14 @@ describe("PublisherService", () => { }, } as NavFormType; const { form } = await publisherService.publishForm(testFormWithNoPublishedLanguages, translations, opts); - expect(form.properties.publishedLanguages).toEqual(["en", "nn-NO"]); + expect(form.properties.publishedLanguages).toEqual(['en', 'nn-NO']); }); - it("resets publishedLanguages when empty translations object is published", async () => { + it('resets publishedLanguages when empty translations object is published', async () => { const testFormWithPublishedLanguages: NavFormType = { ...testForm, properties: { - publishedLanguages: ["en"], + publishedLanguages: ['en'], }, } as NavFormType; const translations = {}; @@ -70,21 +70,21 @@ describe("PublisherService", () => { expect(form.properties.publishedLanguages).toEqual([]); }); - it("does not reset publishedLanguages when translations object is undefined", async () => { + it('does not reset publishedLanguages when translations object is undefined', async () => { const testFormWithPublishedLanguages: NavFormType = { ...testForm, properties: { - publishedLanguages: ["en"], + publishedLanguages: ['en'], }, } as NavFormType; const translations = undefined; const { form } = await publisherService.publishForm(testFormWithPublishedLanguages, translations, opts); - expect(form.properties.publishedLanguages).toEqual(["en"]); + expect(form.properties.publishedLanguages).toEqual(['en']); }); }); }); - describe("when publishing fails", () => { + describe('when publishing fails', () => { // @ts-ignore let formioServiceSpy: vi.SpyInstance< Promise, @@ -98,11 +98,11 @@ describe("PublisherService", () => { formioApiRequestBodies = []; backendMock = { publishForm: () => { - throw new Error("Commit failed"); + throw new Error('Commit failed'); }, } as unknown as Backend; publisherService = new PublisherService(formioService, backendMock); - formioServiceSpy = vi.spyOn(formioService, "saveForm"); + formioServiceSpy = vi.spyOn(formioService, 'saveForm'); nockScope = nock(config.formio.projectUrl) .put(/\/form\/(\d*)$/) .times(2) @@ -117,15 +117,15 @@ describe("PublisherService", () => { expect(nockScope.isDone()).toBe(true); }); - it("form properties are reverted when publish fails", async () => { + it('form properties are reverted when publish fails', async () => { const translations = { en: {} }; - const form: NavFormType = { _id: "2", properties: {} } as NavFormType; + const form: NavFormType = { _id: '2', properties: {} } as NavFormType; let errorThrown = false; try { await publisherService.publishForm(form, translations, opts); } catch (error: any) { errorThrown = true; - expect(error.message).toEqual("Publisering feilet"); + expect(error.message).toBe('Publisering feilet'); } expect(errorThrown).toBe(true); expect(formioServiceSpy).toHaveBeenCalledTimes(2); @@ -140,7 +140,7 @@ describe("PublisherService", () => { expect(formPropsBeforePublish.publishedBy).toEqual(opts.userName); expect(modifiedAtPublish).toBeDefined(); expect(modifiedByAtPublish).toEqual(opts.userName); - expect(formPropsBeforePublish.publishedLanguages).toEqual(["en"]); + expect(formPropsBeforePublish.publishedLanguages).toEqual(['en']); const formPropsRollback = formioApiRequestBodies[1].properties; const modifiedAtRollback = formPropsRollback.modified; @@ -156,9 +156,9 @@ describe("PublisherService", () => { }); }); - describe("unpublishForm", () => { - describe("when unpublish succeeds", () => { - const testGitSha = "123456789A987654321"; + describe('unpublishForm', () => { + describe('when unpublish succeeds', () => { + const testGitSha = '123456789A987654321'; let nockScope: nock.Scope; beforeEach(() => { @@ -174,10 +174,10 @@ describe("PublisherService", () => { expect(nockScope.isDone()).toBe(true); }); - it("sets unpublish props and unsets published props", async () => { + it('sets unpublish props and unsets published props', async () => { const testForm = { - _id: "1", - properties: { published: "2022-07-28T10:00:10.325Z", publishedBy: "ernie" }, + _id: '1', + properties: { published: '2022-07-28T10:00:10.325Z', publishedBy: 'ernie' }, } as NavFormType; const { changed, form } = await publisherService.unpublishForm(testForm, opts); expect(changed).toBe(true); @@ -189,7 +189,7 @@ describe("PublisherService", () => { }); }); - describe("when unpublish fails", () => { + describe('when unpublish fails', () => { let nockScope: nock.Scope; let formioApiRequestBodies: NavFormType[]; @@ -197,7 +197,7 @@ describe("PublisherService", () => { formioApiRequestBodies = []; backendMock = { unpublishForm: () => { - throw new Error("Commit failed"); + throw new Error('Commit failed'); }, } as unknown as Backend; publisherService = new PublisherService(formioService, backendMock); @@ -214,10 +214,10 @@ describe("PublisherService", () => { expect(nockScope.isDone()).toBe(true); }); - it("properties are rolled back", async () => { + it('properties are rolled back', async () => { const testForm = { - _id: "1", - properties: { published: "2022-07-28T10:00:10.325Z", publishedBy: "ernie" }, + _id: '1', + properties: { published: '2022-07-28T10:00:10.325Z', publishedBy: 'ernie' }, } as NavFormType; let errorThrown; @@ -225,7 +225,7 @@ describe("PublisherService", () => { await publisherService.unpublishForm(testForm, opts); } catch (error: any) { errorThrown = true; - expect(error.message).toEqual("Avpublisering feilet"); + expect(error.message).toBe('Avpublisering feilet'); } expect(errorThrown).toBe(true); @@ -240,27 +240,27 @@ describe("PublisherService", () => { }); }); - describe("publishForms (bulk)", () => { + describe('publishForms (bulk)', () => { const testForms: NavFormType[] = [ - { _id: "1", properties: { publishedLanguages: ["en"] } } as unknown as NavFormType, + { _id: '1', properties: { publishedLanguages: ['en'] } } as unknown as NavFormType, { - _id: "2", - properties: { publishedLanguages: [], published: "2022-07-28T10:00:10.325Z", publishedBy: "ernie" }, + _id: '2', + properties: { publishedLanguages: [], published: '2022-07-28T10:00:10.325Z', publishedBy: 'ernie' }, } as unknown as NavFormType, { - _id: "3", + _id: '3', properties: { publishedLanguages: undefined, - modified: "2022-06-28T10:02:15.634Z", - modifiedBy: "bert", - unpublished: "2022-06-28T10:02:15.634Z", - unpublishedBy: "bert", + modified: '2022-06-28T10:02:15.634Z', + modifiedBy: 'bert', + unpublished: '2022-06-28T10:02:15.634Z', + unpublishedBy: 'bert', }, } as unknown as NavFormType, ]; - describe("when bulk publishing succeeds", () => { - const testGitSha = "123456789A987654321"; + describe('when bulk publishing succeeds', () => { + const testGitSha = '123456789A987654321'; let nockScope: nock.Scope; let formioApiRequestBodies: NavFormType[]; @@ -281,12 +281,12 @@ describe("PublisherService", () => { expect(nockScope.isDone()).toBe(true); }); - it("returns git sha for bulk publish commit", async () => { + it('returns git sha for bulk publish commit', async () => { const gitSha = await publisherService.publishForms(testForms, opts); expect(gitSha).toEqual(testGitSha); }); - it("adds properties modified and published with same value", async () => { + it('adds properties modified and published with same value', async () => { await publisherService.publishForms(testForms, opts); expect(formioApiRequestBodies).toHaveLength(3); @@ -313,12 +313,12 @@ describe("PublisherService", () => { expect(form1Published).toEqual(form3Published); }); - it("does not modify publishedLanguages property", async () => { + it('does not modify publishedLanguages property', async () => { await publisherService.publishForms(testForms, opts); expect(formioApiRequestBodies).toHaveLength(3); const form1Props = formioApiRequestBodies[0].properties; - expect(form1Props.publishedLanguages).toEqual(["en"]); + expect(form1Props.publishedLanguages).toEqual(['en']); const form2Props = formioApiRequestBodies[1].properties; expect(form2Props.publishedLanguages).toEqual([]); @@ -328,7 +328,7 @@ describe("PublisherService", () => { }); }); - describe("when publishing fails", () => { + describe('when publishing fails', () => { let nockScope: nock.Scope; let formioApiRequestBodies: NavFormType[]; @@ -336,7 +336,7 @@ describe("PublisherService", () => { formioApiRequestBodies = []; backendMock = { publishForms: () => { - throw new Error("Commit failed"); + throw new Error('Commit failed'); }, } as unknown as Backend; publisherService = new PublisherService(formioService, backendMock); @@ -353,13 +353,13 @@ describe("PublisherService", () => { expect(nockScope.isDone()).toBe(true); }); - it("properties are rolled back", async () => { + it('properties are rolled back', async () => { let errorThrown = false; try { await publisherService.publishForms(testForms, opts); } catch (error: any) { errorThrown = true; - expect(error.message).toEqual("Bulk-publisering feilet"); + expect(error.message).toBe('Bulk-publisering feilet'); } expect(errorThrown).toBe(true); expect(formioApiRequestBodies).toHaveLength(6); diff --git a/packages/bygger-backend/src/services/PublisherService.ts b/packages/bygger-backend/src/services/PublisherService.ts index 4eb7f2621..15c5116a0 100644 --- a/packages/bygger-backend/src/services/PublisherService.ts +++ b/packages/bygger-backend/src/services/PublisherService.ts @@ -3,11 +3,11 @@ import { FormPropertiesPublishing, I18nTranslations, NavFormType, -} from "@navikt/skjemadigitalisering-shared-domain"; -import { Backend } from "../Backend"; -import { logger } from "../logging/logger"; -import { ApiError } from "../routers/api/helpers/errors"; -import { FormioService } from "./formioService"; +} from '@navikt/skjemadigitalisering-shared-domain'; +import { Backend } from '../Backend'; +import { logger } from '../logging/logger'; +import { ApiError } from '../routers/api/helpers/errors'; +import { FormioService } from './formioService'; interface Opts { userName: string; @@ -30,25 +30,25 @@ class PublisherService { const publishedLanguages = translations ? Object.keys(translations) : undefined; const now = dateUtils.getIso8601String(); const formProps = createPublishProps(now, userName, publishedLanguages); - logger.debug("Save form before publishing", { formPath: form.path, ...formProps }); + logger.debug('Save form before publishing', { formPath: form.path, ...formProps }); formWithPublishProps = await this.formioService.saveForm(form, formioToken, userName, formProps); const publishResult = await this.backend.publishForm(formWithPublishProps, translations, form.path); return { changed: !!publishResult, form: formWithPublishProps }; } catch (error) { logger.error(`Failed to publish form`, error); if (formWithPublishProps) { - logger.debug("Rolling back props since publishing failed", { formPath: form.path }); + logger.debug('Rolling back props since publishing failed', { formPath: form.path }); const rollbackFormProps = createRollbackProps(form); try { await this.formioService.saveForm(formWithPublishProps, formioToken, userName, rollbackFormProps); } catch (innerError: any) { - logger.warn("Failed rollback attempt while publishing form", { + logger.warn('Failed rollback attempt while publishing form', { formPath: form.path, errorMessage: innerError.message, }); } } - throw new ApiError("Publisering feilet", true, error as Error); + throw new ApiError('Publisering feilet', true, error as Error); } } @@ -64,11 +64,11 @@ class PublisherService { return { changed: !!gitSha, form: formWithUnpublishProps }; } catch (error) { if (formWithUnpublishProps) { - logger.debug("Rolling back props since unpublishing failed", { formPath: form.path }); + logger.debug('Rolling back props since unpublishing failed', { formPath: form.path }); const rollbackFormProps = createRollbackProps(form); await this.formioService.saveForm(formWithUnpublishProps, formioToken, userName, rollbackFormProps); } - throw new ApiError("Avpublisering feilet", true, error as Error); + throw new ApiError('Avpublisering feilet', true, error as Error); } } @@ -106,7 +106,7 @@ class PublisherService { }), ); } - throw new ApiError("Bulk-publisering feilet", true, error as Error); + throw new ApiError('Bulk-publisering feilet', true, error as Error); } return gitSha; } diff --git a/packages/bygger-backend/src/services/PusherService.ts b/packages/bygger-backend/src/services/PusherService.ts index c3e78d81d..eedab4ef8 100644 --- a/packages/bygger-backend/src/services/PusherService.ts +++ b/packages/bygger-backend/src/services/PusherService.ts @@ -1,6 +1,6 @@ -import Pusher, { Options } from "pusher"; -import config from "../config"; -import { logger } from "../logging/logger"; +import Pusher, { Options } from 'pusher'; +import config from '../config'; +import { logger } from '../logging/logger'; const getPusherConfig = () => { const pusherConfig = { ...config.pusher }; @@ -32,12 +32,12 @@ class PusherService { this.pusher = new Pusher(pusherOptions); } else if (config.isProduction) { - logger.warn("Pusher service not configured"); + logger.warn('Pusher service not configured'); } } trigger(pusherEvent: PusherEvent) { - return this.pusher?.trigger("fyllut-deployment", pusherEvent.type, { + return this.pusher?.trigger('fyllut-deployment', pusherEvent.type, { title: pusherEvent.title, message: pusherEvent.message, }); diff --git a/packages/bygger-backend/src/services/ReportService.test.ts b/packages/bygger-backend/src/services/ReportService.test.ts index c31e31b4b..b3c88606c 100644 --- a/packages/bygger-backend/src/services/ReportService.test.ts +++ b/packages/bygger-backend/src/services/ReportService.test.ts @@ -1,11 +1,11 @@ -import { FormPropertiesType, NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; -import MemoryStream from "memorystream"; -import nock from "nock"; -import config from "../config"; -import ReportService from "./ReportService"; -import { formioService } from "./index"; +import { FormPropertiesType, NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; +import MemoryStream from 'memorystream'; +import nock from 'nock'; +import config from '../config'; +import ReportService from './ReportService'; +import { formioService } from './index'; -describe("ReportService", () => { +describe('ReportService', () => { let reportService: ReportService; beforeEach(() => { @@ -17,29 +17,29 @@ describe("ReportService", () => { nock.cleanAll(); }); - it("returns list containing report metadata", () => { + it('returns list containing report metadata', () => { const allReports = reportService.getAllReports(); - const report = allReports.find((report) => report.id === "forms-published-languages"); + const report = allReports.find((report) => report.id === 'forms-published-languages'); expect(report).toBeDefined(); - expect(report?.title).toEqual("Publiserte språk per skjema"); - expect(report?.contentType).toEqual("text/csv"); + expect(report?.title).toBe('Publiserte språk per skjema'); + expect(report?.contentType).toBe('text/csv'); }); - describe("getReportDefinition", () => { - it("returns report definition for given id", () => { - const reportDefinition = reportService.getReportDefinition("forms-published-languages"); + describe('getReportDefinition', () => { + it('returns report definition for given id', () => { + const reportDefinition = reportService.getReportDefinition('forms-published-languages'); expect(reportDefinition).toBeDefined(); - expect(reportDefinition?.title).toEqual("Publiserte språk per skjema"); + expect(reportDefinition?.title).toBe('Publiserte språk per skjema'); }); - it("returns undefined when id is unknown", () => { - const reportDefinition = reportService.getReportDefinition("unknown-report-id"); + it('returns undefined when id is unknown', () => { + const reportDefinition = reportService.getReportDefinition('unknown-report-id'); expect(reportDefinition).toBeUndefined(); }); }); - describe("Reports", () => { - const CSV_HEADER_LINE = "skjemanummer;skjematittel;språk\n"; + describe('Reports', () => { + const CSV_HEADER_LINE = 'skjemanummer;skjematittel;språk\n'; let nockScope: nock.Scope; @@ -58,9 +58,9 @@ describe("ReportService", () => { }; function parseReport(content: string) { - const allLines = content.split("\n").filter((line) => !!line); - const forms = allLines.slice(1).map((formLine) => formLine.split(";")); - const headers = allLines[0].split(";"); + const allLines = content.split('\n').filter((line) => !!line); + const forms = allLines.slice(1).map((formLine) => formLine.split(';')); + const headers = allLines[0].split(';'); return { headers, forms, @@ -69,156 +69,156 @@ describe("ReportService", () => { }; } - describe("generateFormsPublishedLanguage", () => { - describe("number of signatures", () => { - const HEADER_SIGNATURES = "signaturfelt"; + describe('generateFormsPublishedLanguage', () => { + describe('number of signatures', () => { + const HEADER_SIGNATURES = 'signaturfelt'; - it("defaults to 1 signature", async () => { + it('defaults to 1 signature', async () => { const publishedForms = [ { - title: "Testskjema1", + title: 'Testskjema1', properties: { - skjemanummer: "TEST1", + skjemanummer: 'TEST1', signatures: undefined, } as FormPropertiesType, }, ]; setupNock(publishedForms); const writableStream = createWritableStream(); - await reportService.generate("all-forms-summary", writableStream); + await reportService.generate('all-forms-summary', writableStream); const report = parseReport(writableStream.toString()); - expect(report.numberOfForms).toEqual(1); + expect(report.numberOfForms).toBe(1); const formFields = report.forms[0]; - expect(formFields[report.getHeaderIndex(HEADER_SIGNATURES)]).toEqual("1"); + expect(formFields[report.getHeaderIndex(HEADER_SIGNATURES)]).toBe('1'); }); - it("signature array with default signature", async () => { + it('signature array with default signature', async () => { const publishedForms = [ { - title: "Testskjema1", + title: 'Testskjema1', properties: { - skjemanummer: "TEST1", - signatures: [{ label: "" }], + skjemanummer: 'TEST1', + signatures: [{ label: '' }], } as FormPropertiesType, }, ]; setupNock(publishedForms); const writableStream = createWritableStream(); - await reportService.generate("all-forms-summary", writableStream); + await reportService.generate('all-forms-summary', writableStream); const report = parseReport(writableStream.toString()); - expect(report.numberOfForms).toEqual(1); + expect(report.numberOfForms).toBe(1); const formFields = report.forms[0]; - expect(formFields[report.getHeaderIndex(HEADER_SIGNATURES)]).toEqual("1"); + expect(formFields[report.getHeaderIndex(HEADER_SIGNATURES)]).toBe('1'); }); - it("has 3 signatures", async () => { + it('has 3 signatures', async () => { const publishedForms = [ { - title: "Testskjema1", + title: 'Testskjema1', properties: { - skjemanummer: "TEST1", - signatures: [{ label: "Lege" }, { label: "Verge" }, { label: "Søker" }], + skjemanummer: 'TEST1', + signatures: [{ label: 'Lege' }, { label: 'Verge' }, { label: 'Søker' }], } as FormPropertiesType, }, ]; setupNock(publishedForms); const writableStream = createWritableStream(); - await reportService.generate("all-forms-summary", writableStream); + await reportService.generate('all-forms-summary', writableStream); const report = parseReport(writableStream.toString()); - expect(report.numberOfForms).toEqual(1); + expect(report.numberOfForms).toBe(1); const formFields = report.forms[0]; - expect(formFields[report.getHeaderIndex(HEADER_SIGNATURES)]).toEqual("3"); + expect(formFields[report.getHeaderIndex(HEADER_SIGNATURES)]).toBe('3'); }); }); - describe("unpublished changes", () => { - const HEADER_UNPUBLISHED_CHANGES = "upubliserte endringer"; + describe('unpublished changes', () => { + const HEADER_UNPUBLISHED_CHANGES = 'upubliserte endringer'; - it("has no unpublished changes", async () => { + it('has no unpublished changes', async () => { const publishedForms = [ { - title: "Testskjema1", + title: 'Testskjema1', properties: { - skjemanummer: "TEST1", - published: "2022-07-28T10:00:10.325Z", - modified: "2022-07-28T10:00:10.325Z", + skjemanummer: 'TEST1', + published: '2022-07-28T10:00:10.325Z', + modified: '2022-07-28T10:00:10.325Z', } as FormPropertiesType, }, ]; setupNock(publishedForms); const writableStream = createWritableStream(); - await reportService.generate("all-forms-summary", writableStream); + await reportService.generate('all-forms-summary', writableStream); const report = parseReport(writableStream.toString()); - expect(report.numberOfForms).toEqual(1); + expect(report.numberOfForms).toBe(1); const formFields = report.forms[0]; - expect(formFields[report.getHeaderIndex(HEADER_UNPUBLISHED_CHANGES)]).toEqual("nei"); + expect(formFields[report.getHeaderIndex(HEADER_UNPUBLISHED_CHANGES)]).toBe('nei'); }); - it("has unpublished changes", async () => { + it('has unpublished changes', async () => { const publishedForms = [ { - title: "Testskjema1", + title: 'Testskjema1', properties: { - skjemanummer: "TEST1", - published: "2022-07-28T10:00:10.325Z", - modified: "2022-07-28T11:00:05.254Z", + skjemanummer: 'TEST1', + published: '2022-07-28T10:00:10.325Z', + modified: '2022-07-28T11:00:05.254Z', } as FormPropertiesType, }, ]; setupNock(publishedForms); const writableStream = createWritableStream(); - await reportService.generate("all-forms-summary", writableStream); + await reportService.generate('all-forms-summary', writableStream); const report = parseReport(writableStream.toString()); - expect(report.numberOfForms).toEqual(1); + expect(report.numberOfForms).toBe(1); const formFields = report.forms[0]; - expect(formFields[report.getHeaderIndex(HEADER_UNPUBLISHED_CHANGES)]).toEqual("ja"); + expect(formFields[report.getHeaderIndex(HEADER_UNPUBLISHED_CHANGES)]).toBe('ja'); }); - it("shows no information about unpublished changes for unpublished forms", async () => { + it('shows no information about unpublished changes for unpublished forms', async () => { const publishedForms = [ { - title: "Testskjema1", + title: 'Testskjema1', properties: { - skjemanummer: "TEST1", - modified: "2022-07-28T11:00:05.254Z", + skjemanummer: 'TEST1', + modified: '2022-07-28T11:00:05.254Z', } as FormPropertiesType, }, ]; setupNock(publishedForms); const writableStream = createWritableStream(); - await reportService.generate("all-forms-summary", writableStream); + await reportService.generate('all-forms-summary', writableStream); const report = parseReport(writableStream.toString()); - expect(report.numberOfForms).toEqual(1); + expect(report.numberOfForms).toBe(1); const formFields = report.forms[0]; - expect(formFields[report.getHeaderIndex(HEADER_UNPUBLISHED_CHANGES)]).toEqual(""); + expect(formFields[report.getHeaderIndex(HEADER_UNPUBLISHED_CHANGES)]).toBe(''); }); }); }); - describe("generateAllFormsSummary", () => { - it("includes published forms with its respective languages", async () => { + describe('generateAllFormsSummary', () => { + it('includes published forms with its respective languages', async () => { const publishedForms = [ { - title: "Testskjema1", + title: 'Testskjema1', properties: { - skjemanummer: "TEST1", - published: "2022-07-28T10:00:10.325Z", - publishedLanguages: ["en", "nn-NO"], + skjemanummer: 'TEST1', + published: '2022-07-28T10:00:10.325Z', + publishedLanguages: ['en', 'nn-NO'], } as FormPropertiesType, }, { - title: "Testskjema2", + title: 'Testskjema2', properties: { - skjemanummer: "TEST2", - published: "2022-07-28T10:00:10.325Z", - publishedLanguages: ["en"], + skjemanummer: 'TEST2', + published: '2022-07-28T10:00:10.325Z', + publishedLanguages: ['en'], } as FormPropertiesType, }, { - title: "Testskjema3", + title: 'Testskjema3', properties: { - skjemanummer: "TEST3", - published: "2022-07-28T10:00:10.325Z", + skjemanummer: 'TEST3', + published: '2022-07-28T10:00:10.325Z', publishedLanguages: undefined, } as FormPropertiesType, }, @@ -226,28 +226,28 @@ describe("ReportService", () => { setupNock(publishedForms); const writableStream = createWritableStream(); - await reportService.generate("forms-published-languages", writableStream); + await reportService.generate('forms-published-languages', writableStream); expect(writableStream.toString()).toEqual( - CSV_HEADER_LINE + "TEST1;Testskjema1;en,nn-NO\nTEST2;Testskjema2;en\nTEST3;Testskjema3;\n", + CSV_HEADER_LINE + 'TEST1;Testskjema1;en,nn-NO\nTEST2;Testskjema2;en\nTEST3;Testskjema3;\n', ); }); - it("does not include testform", async () => { + it('does not include testform', async () => { const publishedForms = [ { - title: "Testskjema1", + title: 'Testskjema1', properties: { - skjemanummer: "TEST1", - published: "2022-07-28T10:00:10.325Z", - publishedLanguages: ["en", "nn-NO"], + skjemanummer: 'TEST1', + published: '2022-07-28T10:00:10.325Z', + publishedLanguages: ['en', 'nn-NO'], } as FormPropertiesType, }, { - title: "Testskjema2", + title: 'Testskjema2', properties: { - skjemanummer: "TEST2", - published: "2022-07-28T10:00:10.325Z", - publishedLanguages: ["en"], + skjemanummer: 'TEST2', + published: '2022-07-28T10:00:10.325Z', + publishedLanguages: ['en'], isTestForm: true, // <- testform } as FormPropertiesType, }, @@ -255,15 +255,15 @@ describe("ReportService", () => { setupNock(publishedForms); const writableStream = createWritableStream(); - await reportService.generate("forms-published-languages", writableStream); - expect(writableStream.toString()).toEqual(CSV_HEADER_LINE + "TEST1;Testskjema1;en,nn-NO\n"); + await reportService.generate('forms-published-languages', writableStream); + expect(writableStream.toString()).toEqual(CSV_HEADER_LINE + 'TEST1;Testskjema1;en,nn-NO\n'); }); - it("fails if unknown report", async () => { + it('fails if unknown report', async () => { let errorCatched = false; const writableStream = createWritableStream(); try { - await reportService.generate("unknown-report-id", writableStream); + await reportService.generate('unknown-report-id', writableStream); } catch (err) { errorCatched = true; } diff --git a/packages/bygger-backend/src/services/ReportService.ts b/packages/bygger-backend/src/services/ReportService.ts index ddc059a15..b6af5836d 100644 --- a/packages/bygger-backend/src/services/ReportService.ts +++ b/packages/bygger-backend/src/services/ReportService.ts @@ -1,27 +1,27 @@ -import { NavFormType, ReportDefinition } from "@navikt/skjemadigitalisering-shared-domain"; -import { stringify } from "csv-stringify"; -import { DateTime } from "luxon"; -import { Writable } from "stream"; -import { FormioService } from "./formioService"; +import { NavFormType, ReportDefinition } from '@navikt/skjemadigitalisering-shared-domain'; +import { stringify } from 'csv-stringify'; +import { DateTime } from 'luxon'; +import { Writable } from 'stream'; +import { FormioService } from './formioService'; const ReportMap: Record = { FORMS_PUBLISHED_LANGUAGES: { - id: "forms-published-languages", - title: "Publiserte språk per skjema", - contentType: "text/csv", - fileEnding: "csv", + id: 'forms-published-languages', + title: 'Publiserte språk per skjema', + contentType: 'text/csv', + fileEnding: 'csv', }, ALL_FORMS_SUMMARY: { - id: "all-forms-summary", - title: "Alle skjema med nøkkelinformasjon", - contentType: "text/csv", - fileEnding: "csv", + id: 'all-forms-summary', + title: 'Alle skjema med nøkkelinformasjon', + contentType: 'text/csv', + fileEnding: 'csv', }, UNPUBLISHED_FORMS: { - id: "unpublished-forms", - title: "Avpubliserte skjema", - contentType: "text/csv", - fileEnding: "csv", + id: 'unpublished-forms', + title: 'Avpubliserte skjema', + contentType: 'text/csv', + fileEnding: 'csv', }, }; @@ -54,13 +54,13 @@ class ReportService { } private async generateFormsPublishedLanguage(writableStream: Writable) { - const columns = ["skjemanummer", "skjematittel", "språk"]; - const publishedForms = await this.formioService.getPublishedForms("title,properties"); - const stringifier = stringify({ header: true, columns, delimiter: ";" }); + const columns = ['skjemanummer', 'skjematittel', 'språk']; + const publishedForms = await this.formioService.getPublishedForms('title,properties'); + const stringifier = stringify({ header: true, columns, delimiter: ';' }); stringifier.pipe(writableStream); publishedForms.filter(notTestForm).forEach((form) => { const { title, properties } = form; - const publishedLanguages = properties.publishedLanguages?.join(",") || ""; + const publishedLanguages = properties.publishedLanguages?.join(',') || ''; stringifier.write([properties.skjemanummer, title, publishedLanguages]); }); stringifier.end(); @@ -68,29 +68,29 @@ class ReportService { private async generateAllFormsSummary(writableStream: Writable) { const columns = [ - "skjemanummer", - "skjematittel", - "tema", - "sist publisert", - "publisert av", - "upubliserte endringer", - "sist endret", - "endret av", - "innsending", - "signaturfelt", - "path", + 'skjemanummer', + 'skjematittel', + 'tema', + 'sist publisert', + 'publisert av', + 'upubliserte endringer', + 'sist endret', + 'endret av', + 'innsending', + 'signaturfelt', + 'path', ]; - const allForms = await this.formioService.getAllForms(undefined, true, "title,path,properties"); - const stringifier = stringify({ header: true, columns, delimiter: ";" }); + const allForms = await this.formioService.getAllForms(undefined, true, 'title,path,properties'); + const stringifier = stringify({ header: true, columns, delimiter: ';' }); stringifier.pipe(writableStream); allForms.filter(notTestForm).forEach((form) => { const { title, properties, path } = form; const { published, publishedBy, modified, modifiedBy, innsending, tema, signatures } = properties; - let unpublishedChanges: string = ""; + let unpublishedChanges: string = ''; if (modified && published) { const modifiedDate = DateTime.fromISO(modified); const publishedDate = DateTime.fromISO(published); - unpublishedChanges = publishedDate.until(modifiedDate).isEmpty() ? "nei" : "ja"; + unpublishedChanges = publishedDate.until(modifiedDate).isEmpty() ? 'nei' : 'ja'; } const numberOfSignatures = signatures?.length || 1; stringifier.write([ @@ -111,9 +111,9 @@ class ReportService { } private async generateUnpublishedForms(writableStream: Writable) { - const columns = ["skjemanummer", "skjematittel", "avpublisert", "avpublisert av"]; - const publishedForms = await this.formioService.getUnpublishedForms("title,properties"); - const stringifier = stringify({ header: true, columns, delimiter: ";" }); + const columns = ['skjemanummer', 'skjematittel', 'avpublisert', 'avpublisert av']; + const publishedForms = await this.formioService.getUnpublishedForms('title,properties'); + const stringifier = stringify({ header: true, columns, delimiter: ';' }); stringifier.pipe(writableStream); publishedForms.filter(notTestForm).forEach((form) => { const { title, properties } = form; diff --git a/packages/bygger-backend/src/services/formioService.test.ts b/packages/bygger-backend/src/services/formioService.test.ts index cfa083ac8..12a86cd24 100644 --- a/packages/bygger-backend/src/services/formioService.test.ts +++ b/packages/bygger-backend/src/services/formioService.test.ts @@ -1,16 +1,16 @@ -import { NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; -import nock from "nock"; -import config from "../config"; -import { formioService } from "./index"; +import { NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; +import nock from 'nock'; +import config from '../config'; +import { formioService } from './index'; -describe("FormioService", () => { - describe("saveForm", () => { - describe("props modified and modifiedBy", () => { +describe('FormioService', () => { + describe('saveForm', () => { + describe('props modified and modifiedBy', () => { const form: NavFormType = { - _id: "1", + _id: '1', properties: { - modified: "2022-06-28T10:02:15.634Z", - modifiedBy: "dennis", + modified: '2022-06-28T10:02:15.634Z', + modifiedBy: 'dennis', }, } as NavFormType; @@ -24,30 +24,30 @@ describe("FormioService", () => { nock.cleanAll(); }); - it("are updated with new values", async () => { - const savedForm = await formioService.saveForm(form, "formio-token", "tore"); + it('are updated with new values', async () => { + const savedForm = await formioService.saveForm(form, 'formio-token', 'tore'); expect(savedForm.properties.modified).not.toEqual(form.properties.modified); - expect(savedForm.properties.modifiedBy).toEqual("tore"); + expect(savedForm.properties.modifiedBy).toBe('tore'); }); - it("are updated with values specified in formProps parameter", async () => { + it('are updated with values specified in formProps parameter', async () => { const props = { - modified: "2022-06-28T10:03:15.634Z", - modifiedBy: "pia", + modified: '2022-06-28T10:03:15.634Z', + modifiedBy: 'pia', }; - const savedForm = await formioService.saveForm(form, "formio-token", "tore", props); + const savedForm = await formioService.saveForm(form, 'formio-token', 'tore', props); expect(savedForm.properties.modified).not.toEqual(form.properties.modified); expect(savedForm.properties.modified).toEqual(props.modified); - expect(savedForm.properties.modifiedBy).toEqual("pia"); + expect(savedForm.properties.modifiedBy).toBe('pia'); }); }); - describe("http error from formio api", () => { + describe('http error from formio api', () => { beforeEach(() => { nock(config.formio.projectUrl) .put(/\/form\/(\d*)$/) .reply(500); - vi.spyOn(console, "error").mockImplementation(() => {}); + vi.spyOn(console, 'error').mockImplementation(() => {}); }); afterEach(() => { @@ -55,24 +55,24 @@ describe("FormioService", () => { vi.restoreAllMocks(); }); - it("is thrown as an error", async () => { + it('is thrown as an error', async () => { const form: NavFormType = { - _id: "1", + _id: '1', properties: {}, } as NavFormType; let error; try { - await formioService.saveForm(form, "formio-token", "tore"); + await formioService.saveForm(form, 'formio-token', 'tore'); } catch (e) { error = e; } expect(error).toBeDefined(); - expect(error?.response?.status).toEqual(500); + expect(error?.response?.status).toBe(500); }); }); }); - describe("saveForms", () => { + describe('saveForms', () => { beforeEach(() => { nock(config.formio.projectUrl) .put(/\/form\/(\d*)$/) @@ -84,12 +84,12 @@ describe("FormioService", () => { nock.cleanAll(); }); - it("uses same modified and modifiedBy on all forms", async () => { + it('uses same modified and modifiedBy on all forms', async () => { const forms = [ - { _id: "1", properties: { modified: "2022-06-28T10:03:15.634Z" } } as NavFormType, - { _id: "2", properties: { modified: "2022-06-06T12:55:05.000Z" } } as NavFormType, + { _id: '1', properties: { modified: '2022-06-28T10:03:15.634Z' } } as NavFormType, + { _id: '2', properties: { modified: '2022-06-06T12:55:05.000Z' } } as NavFormType, ]; - const savedForms = await formioService.saveForms(forms, "formio-token", "jenny"); + const savedForms = await formioService.saveForms(forms, 'formio-token', 'jenny'); expect(savedForms).toHaveLength(2); expect(savedForms[0].properties.modified).toEqual(savedForms[1].properties.modified); }); diff --git a/packages/bygger-backend/src/services/formioService.ts b/packages/bygger-backend/src/services/formioService.ts index c4f7cb121..5b2539e7f 100644 --- a/packages/bygger-backend/src/services/formioService.ts +++ b/packages/bygger-backend/src/services/formioService.ts @@ -4,8 +4,8 @@ import { FormPropertiesType, NavFormType, navFormUtils, -} from "@navikt/skjemadigitalisering-shared-domain"; -import { fetchWithErrorHandling } from "../fetchUtils"; +} from '@navikt/skjemadigitalisering-shared-domain'; +import { fetchWithErrorHandling } from '../fetchUtils'; export class FormioService { private readonly projectUrl: string; @@ -16,7 +16,7 @@ export class FormioService { async fetchFromProjectApi(path: string): Promise { const response = await fetchWithErrorHandling(`${this.projectUrl}${path}`, { - headers: { "Content-Type": "application/json" }, + headers: { 'Content-Type': 'application/json' }, }); return response.data; } @@ -30,21 +30,21 @@ export class FormioService { return this.fetchFromProjectApi(`/form?type=form&path__in=${formPaths.toString()}&limit=${limit}`); } - async getPublishedForms(select = "", limit = 1000): Promise { + async getPublishedForms(select = '', limit = 1000): Promise { return this.fetchFromProjectApi( `/form?type=form&tags=nav-skjema&properties.published__exists=true&select=${select}&limit=${limit}`, ); } - async getUnpublishedForms(select = "", limit = 1000): Promise { + async getUnpublishedForms(select = '', limit = 1000): Promise { return this.fetchFromProjectApi( `/form?type=form&tags=nav-skjema&properties.unpublished__exists=true&select=${select}&limit=${limit}`, ); } - async getAllForms(limit = 1000, excludeDeleted = true, select = ""): Promise { + async getAllForms(limit = 1000, excludeDeleted = true, select = ''): Promise { return this.fetchFromProjectApi( - `/form?type=form${excludeDeleted ? "&tags=nav-skjema" : ""}&select=${select}&limit=${limit}`, + `/form?type=form${excludeDeleted ? '&tags=nav-skjema' : ''}&select=${select}&limit=${limit}`, ); } @@ -52,8 +52,8 @@ export class FormioService { const currentUserUrl = `${this.projectUrl}/current`; const response = await fetchWithErrorHandling(currentUserUrl, { headers: { - "Content-Type": "application/json", - "x-jwt-token": userToken, + 'Content-Type': 'application/json', + 'x-jwt-token': userToken, }, }); return response.data; @@ -77,10 +77,10 @@ export class FormioService { const enrichedForm = enrichComponents ? addNavIdToComponents(form) : form; const formWithProps = updateProps(enrichedForm, props); const response: any = await fetchWithErrorHandling(`${updateFormUrl}/${form._id}`, { - method: "PUT", + method: 'PUT', headers: { - "Content-Type": "application/json", - "x-jwt-token": formioToken, + 'Content-Type': 'application/json', + 'x-jwt-token': formioToken, }, body: JSON.stringify(formWithProps), }); diff --git a/packages/bygger-backend/src/services/index.ts b/packages/bygger-backend/src/services/index.ts index b41ae1aaf..510a4b66f 100644 --- a/packages/bygger-backend/src/services/index.ts +++ b/packages/bygger-backend/src/services/index.ts @@ -1,9 +1,9 @@ -import { Backend } from "../Backend"; -import config from "../config"; -import { FormioService } from "./formioService"; -import PublisherService from "./PublisherService"; -import PusherService from "./PusherService"; -import ReportService from "./ReportService"; +import { Backend } from '../Backend'; +import config from '../config'; +import { FormioService } from './formioService'; +import PublisherService from './PublisherService'; +import PusherService from './PusherService'; +import ReportService from './ReportService'; const formioService = new FormioService(config.formio.projectUrl); @@ -15,4 +15,4 @@ const reportService = new ReportService(formioService); const pusherService = new PusherService(); -export { formioService, publisherService, pusherService, reportService, backendInstance }; +export { backendInstance, formioService, publisherService, pusherService, reportService }; diff --git a/packages/bygger-backend/src/setupTests.ts b/packages/bygger-backend/src/setupTests.ts index 24fbadc15..f65bab6a8 100644 --- a/packages/bygger-backend/src/setupTests.ts +++ b/packages/bygger-backend/src/setupTests.ts @@ -1,7 +1,7 @@ -import dotenv from "dotenv"; -import nock from "nock"; +import dotenv from 'dotenv'; +import nock from 'nock'; -dotenv.config({ path: "./src/test/test.env" }); +dotenv.config({ path: './src/test/test.env' }); nock.disableNetConnect(); -nock.enableNetConnect("127.0.0.1"); +nock.enableNetConnect('127.0.0.1'); diff --git a/packages/bygger-backend/src/test/testHelpers.ts b/packages/bygger-backend/src/test/testHelpers.ts index 8c5b883cf..f1d7368f1 100644 --- a/packages/bygger-backend/src/test/testHelpers.ts +++ b/packages/bygger-backend/src/test/testHelpers.ts @@ -1,10 +1,10 @@ -import { Request, Response } from "express"; -import jwt from "jsonwebtoken"; -import jose from "node-jose"; +import { Request, Response } from 'express'; +import jwt from 'jsonwebtoken'; +import jose from 'node-jose'; const keystore = jose.JWK.createKeyStore(); -export const generateJwk = async () => keystore.generate("RSA", 2048); +export const generateJwk = async () => keystore.generate('RSA', 2048); export function mockResponse(): Response { return { @@ -28,14 +28,14 @@ export function mockRequest({ headers = {}, params = {}, body }: MockRequestData } as unknown as Request; } -export const createMockJwt = (payload: object, key: jose.JWK.Key, expiresIn = "5m") => { +export const createMockJwt = (payload: object, key: jose.JWK.Key, expiresIn = '5m') => { const obj = { - token_type: "Bearer", + token_type: 'Bearer', ...payload, }; return createAccessToken(obj, expiresIn, key); }; const createAccessToken = async (payload: object, expiresIn: string, key: jose.JWK.Key) => { - return jwt.sign(payload, key.toPEM(true), { expiresIn, algorithm: "RS256" }); + return jwt.sign(payload, key.toPEM(true), { expiresIn, algorithm: 'RS256' }); }; diff --git a/packages/bygger-backend/src/testdata/default-github-push-event.ts b/packages/bygger-backend/src/testdata/default-github-push-event.ts index d8a67bf22..3d2d0eb9a 100644 --- a/packages/bygger-backend/src/testdata/default-github-push-event.ts +++ b/packages/bygger-backend/src/testdata/default-github-push-event.ts @@ -1,23 +1,23 @@ -import { PushEvent } from "@octokit/webhooks-types"; +import { PushEvent } from '@octokit/webhooks-types'; const defaultGithubPushEvent = { head_commit: { author: { - email: "homer.simpson@mail.com", - name: "Homer Simpson", - username: "hsimpson", + email: 'homer.simpson@mail.com', + name: 'Homer Simpson', + username: 'hsimpson', }, committer: { - email: "noreply@github.com", - name: "GitHub", - username: "web-flow", + email: 'noreply@github.com', + name: 'GitHub', + username: 'web-flow', }, distinct: true, - id: "87324lkasjho384nalno3wiuoaw93", - message: "Tjo-hoo!", - timestamp: "2021-08-23T10:46:12+02:00", - tree_id: "a3aowo34ja3a3whlhaw3lhlaw3lawleøcra93uma", - url: "https://github.com/hsimpson/funny-repo/commit/05207b66223e524267161b099bddbf9be4b312f0", + id: '87324lkasjho384nalno3wiuoaw93', + message: 'Tjo-hoo!', + timestamp: '2021-08-23T10:46:12+02:00', + tree_id: 'a3aowo34ja3a3whlhaw3lhlaw3lawleøcra93uma', + url: 'https://github.com/hsimpson/funny-repo/commit/05207b66223e524267161b099bddbf9be4b312f0', }, }; const pushEventWithCommitMessage = (commitMessage: string): PushEvent => { diff --git a/packages/bygger-backend/src/types.d.ts b/packages/bygger-backend/src/types.d.ts index 818d79fc8..3785d2cfe 100644 --- a/packages/bygger-backend/src/types.d.ts +++ b/packages/bygger-backend/src/types.d.ts @@ -1,4 +1,4 @@ -import { Request } from "express"; +import { Request } from 'express'; interface User { name: string; diff --git a/packages/bygger-backend/src/types/custom.ts b/packages/bygger-backend/src/types/custom.ts index 2c5fcdfb3..fdbf53a3e 100644 --- a/packages/bygger-backend/src/types/custom.ts +++ b/packages/bygger-backend/src/types/custom.ts @@ -1,4 +1,4 @@ -import { JWTPayload } from "jose"; +import { JWTPayload } from 'jose'; export type User = { name: string; diff --git a/packages/bygger-backend/src/types/express/index.d.ts b/packages/bygger-backend/src/types/express/index.d.ts index ffcd5f6f5..6ca8ab147 100644 --- a/packages/bygger-backend/src/types/express/index.d.ts +++ b/packages/bygger-backend/src/types/express/index.d.ts @@ -1,4 +1,4 @@ -import { User } from "../custom"; +import { User } from '../custom'; declare global { namespace Express { diff --git a/packages/bygger-backend/src/types/migration.d.ts b/packages/bygger-backend/src/types/migration.d.ts index 659c1c27e..4117ec08b 100644 --- a/packages/bygger-backend/src/types/migration.d.ts +++ b/packages/bygger-backend/src/types/migration.d.ts @@ -1,4 +1,4 @@ -import { DependencyType, FormPropertiesType, NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; +import { DependencyType, FormPropertiesType, NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; // se duplikat: bygger/types/migration.d.ts export type ParsedInput = number | string | boolean | null | object | Array; @@ -48,17 +48,17 @@ export interface Dependencies { export interface FormMigrationLogData extends Pick< FormPropertiesType, - | "skjemanummer" - | "modified" - | "modifiedBy" - | "published" - | "publishedBy" - | "unpublishedBy" - | "isTestForm" - | "unpublished" - | "publishedLanguages" + | 'skjemanummer' + | 'modified' + | 'modifiedBy' + | 'published' + | 'publishedBy' + | 'unpublishedBy' + | 'isTestForm' + | 'unpublished' + | 'publishedLanguages' >, - Pick { + Pick { found: number; changed: number; diff: FormMigrationDiff[]; diff --git a/packages/bygger-backend/src/util/devUser.ts b/packages/bygger-backend/src/util/devUser.ts index 16a12c91e..5f6f64d5f 100644 --- a/packages/bygger-backend/src/util/devUser.ts +++ b/packages/bygger-backend/src/util/devUser.ts @@ -1,12 +1,12 @@ -import { Request } from "express"; -import { formioService } from "../services"; -import { User } from "../types/custom"; -import { getFormioToken } from "./requestTool"; +import { Request } from 'express'; +import { formioService } from '../services'; +import { User } from '../types/custom'; +import { getFormioToken } from './requestTool'; const devUser = { - name: "dev-user", - preferredUsername: "dev-user-preferred", - NAVident: "dev-navident", + name: 'dev-user', + preferredUsername: 'dev-user-preferred', + NAVident: 'dev-navident', isAdmin: true, }; @@ -18,12 +18,12 @@ export const getDevUser = async (req: Request): Promise => { return { name: formioUser.data.email, preferredUsername: formioUser.data.email, - NAVident: "N/A", + NAVident: 'N/A', isAdmin: true, }; } catch (e) { // @ts-ignore - console.error("Error while fetching dev user:", e.message); + console.error('Error while fetching dev user:', e.message); } } return devUser; diff --git a/packages/bygger-backend/src/util/errorToJson.js b/packages/bygger-backend/src/util/errorToJson.js index 89798c160..2ba3b1daa 100644 --- a/packages/bygger-backend/src/util/errorToJson.js +++ b/packages/bygger-backend/src/util/errorToJson.js @@ -1,6 +1,6 @@ /* eslint-disable no-extend-native */ -if (!("toJSON" in Error.prototype)) { - Object.defineProperty(Error.prototype, "toJSON", { +if (!('toJSON' in Error.prototype)) { + Object.defineProperty(Error.prototype, 'toJSON', { value: function () { var alt = {}; diff --git a/packages/bygger-backend/src/util/logUtils.test.ts b/packages/bygger-backend/src/util/logUtils.test.ts index acb824b09..91f42b375 100644 --- a/packages/bygger-backend/src/util/logUtils.test.ts +++ b/packages/bygger-backend/src/util/logUtils.test.ts @@ -1,42 +1,42 @@ -import { toMeta } from "./logUtils"; +import { toMeta } from './logUtils'; -describe("logUtils", () => { - describe("toMeta", () => { - it("adds prefix to meta object for logging", () => { - const result = toMeta("coffee", { title: "en overskrift", message: "en melding" }); +describe('logUtils', () => { + describe('toMeta', () => { + it('adds prefix to meta object for logging', () => { + const result = toMeta('coffee', { title: 'en overskrift', message: 'en melding' }); expect(result).toEqual({ - coffee_title: "en overskrift", - coffee_message: "en melding", + coffee_title: 'en overskrift', + coffee_message: 'en melding', }); }); - it("flattens and adds prefix", () => { - const result = toMeta("coffee", { - title: "en overskrift", + it('flattens and adds prefix', () => { + const result = toMeta('coffee', { + title: 'en overskrift', black: { one: false, - two: "morning", + two: 'morning', }, }); expect(result).toEqual({ - coffee_title: "en overskrift", + coffee_title: 'en overskrift', coffee_black_one: false, - coffee_black_two: "morning", + coffee_black_two: 'morning', }); }); - it("handles obj undefined", () => { - const result = toMeta("coffee", undefined); + it('handles obj undefined', () => { + const result = toMeta('coffee', undefined); expect(result).toEqual({ coffee: undefined }); }); - it("handles obj null", () => { - const result = toMeta("coffee", null); + it('handles obj null', () => { + const result = toMeta('coffee', null); expect(result).toEqual({ coffee: null }); }); - it("handles empty object", () => { - const result = toMeta("coffee", {}); + it('handles empty object', () => { + const result = toMeta('coffee', {}); expect(result).toEqual({ coffee: {} }); }); }); diff --git a/packages/bygger-backend/src/util/logUtils.ts b/packages/bygger-backend/src/util/logUtils.ts index 7881406fa..b4e4dc0be 100644 --- a/packages/bygger-backend/src/util/logUtils.ts +++ b/packages/bygger-backend/src/util/logUtils.ts @@ -6,7 +6,7 @@ const processObject = (prefix: string, obj: object | undefined | null): { [k: st .map((key: string) => { // @ts-ignore const value = obj[key]; - if (typeof value === "object") { + if (typeof value === 'object') { return processObject(`${prefix}_${key}`, value); } return { [`${prefix}_${key}`]: value }; diff --git a/packages/bygger-backend/src/util/requestTool.ts b/packages/bygger-backend/src/util/requestTool.ts index a2e39ac82..80d0c582c 100644 --- a/packages/bygger-backend/src/util/requestTool.ts +++ b/packages/bygger-backend/src/util/requestTool.ts @@ -1,7 +1,7 @@ -import { Request } from "express"; +import { Request } from 'express'; const getFormioToken = (req: Request) => { - return req.get("Bygger-Formio-Token") ?? req.body?.token; + return req.get('Bygger-Formio-Token') ?? req.body?.token; }; export { getFormioToken }; diff --git a/packages/bygger-backend/testTools/backend/testUtils.js b/packages/bygger-backend/testTools/backend/testUtils.js index c412971df..72c5ec309 100644 --- a/packages/bygger-backend/testTools/backend/testUtils.js +++ b/packages/bygger-backend/testTools/backend/testUtils.js @@ -1,26 +1,26 @@ -import { Backend } from "../../src/Backend"; -import { FormioService } from "../../src/services/formioService"; +import { Backend } from '../../src/Backend'; +import { FormioService } from '../../src/services/formioService'; -const { Response } = await vi.importActual("node-fetch"); +const { Response } = await vi.importActual('node-fetch'); -const FORMIO_PROJECT_URL = "https://projectApi.example.com"; +const FORMIO_PROJECT_URL = 'https://projectApi.example.com'; export const configForTest = { formio: { projectUrl: FORMIO_PROJECT_URL, }, publishRepo: { - owner: "publish-repo-owner", - name: "publish-repo", - base: "publish-repo-main-branch", - token: "publishRepoToken", + owner: 'publish-repo-owner', + name: 'publish-repo', + base: 'publish-repo-main-branch', + token: 'publishRepoToken', }, - gitSha: "publish-repo-git-sha", + gitSha: 'publish-repo-git-sha', githubApp: { - appId: "test", - clientId: "id", - clientSecret: "secret", - privateKey: "privateKey", + appId: 'test', + clientId: 'id', + clientSecret: 'secret', + privateKey: 'privateKey', }, }; diff --git a/packages/bygger-backend/vite.config.ts b/packages/bygger-backend/vite.config.ts index 7bd912771..1221a0919 100644 --- a/packages/bygger-backend/vite.config.ts +++ b/packages/bygger-backend/vite.config.ts @@ -1,17 +1,17 @@ /// -import { defineConfig, PluginOption } from "vite"; -import { VitePluginNode } from "vite-plugin-node"; -import tsconfigPaths from "vite-tsconfig-paths"; +import { defineConfig, PluginOption } from 'vite'; +import { VitePluginNode } from 'vite-plugin-node'; +import tsconfigPaths from 'vite-tsconfig-paths'; export default defineConfig(({ mode }) => { const plugins: PluginOption = [ ...VitePluginNode({ - adapter: "express", - appPath: "./src/server.js", + adapter: 'express', + appPath: './src/server.js', }), ]; - if (mode !== "production") { + if (mode !== 'production') { plugins.push(tsconfigPaths()); } @@ -26,17 +26,17 @@ export default defineConfig(({ mode }) => { }, build: { rollupOptions: { - input: "./src/server.js", + input: './src/server.js', output: { - entryFileNames: "[name].mjs", + entryFileNames: '[name].mjs', }, }, }, plugins, test: { globals: true, - setupFiles: "./src/setupTests.ts", - include: ["src/(**/)?*.test.[jt]s(x)?"], + setupFiles: './src/setupTests.ts', + include: ['src/(**/)?*.test.[jt]s(x)?'], }, }; }); diff --git a/packages/bygger/cypress.config.ts b/packages/bygger/cypress.config.ts index cea185227..c9f402e3e 100644 --- a/packages/bygger/cypress.config.ts +++ b/packages/bygger/cypress.config.ts @@ -1,12 +1,11 @@ -import { defineConfig } from "cypress"; +import { defineConfig } from 'cypress'; export default defineConfig({ video: false, e2e: { - baseUrl: "http://localhost:3000", + baseUrl: 'http://localhost:3000', viewportWidth: 1280, viewportHeight: 1000, testIsolation: false, - setupNodeEvents(on, config) {}, }, }); diff --git a/packages/bygger/cypress/e2e/diff.spec.cy.ts b/packages/bygger/cypress/e2e/diff.spec.cy.ts index 0dd4be873..3365910c5 100644 --- a/packages/bygger/cypress/e2e/diff.spec.cy.ts +++ b/packages/bygger/cypress/e2e/diff.spec.cy.ts @@ -1,144 +1,144 @@ const clickBuilderComponentButton = (title) => () => { - cy.findAllByTitle(title).first().should("exist").click({ force: true }); // force because these buttons are only visible on hover + cy.findAllByTitle(title).first().should('exist').click({ force: true }); // force because these buttons are only visible on hover }; -describe("Diff", () => { +describe('Diff', () => { beforeEach(() => { - cy.intercept("GET", "/api/config", { fixture: "config.json" }).as("getConfig"); - cy.intercept("GET", "/form?*", { fixture: "form123456.json" }).as("getForm"); - cy.intercept("GET", "/api/published-forms/dif123456", { fixture: "form123456-published.json" }).as( - "getPublishedForm", + cy.intercept('GET', '/api/config', { fixture: 'config.json' }).as('getConfig'); + cy.intercept('GET', '/form?*', { fixture: 'form123456.json' }).as('getForm'); + cy.intercept('GET', '/api/published-forms/dif123456', { fixture: 'form123456-published.json' }).as( + 'getPublishedForm', ); - cy.intercept("GET", "/mottaksadresse/submission", { fixture: "mottakadresse.json" }).as("getMottakAdresse"); - cy.intercept("GET", /language\/submission?.*/, { fixture: "globalTranslations.json" }).as("getTranslations"); - cy.intercept("GET", "/api/temakoder", { fixture: "temakoder.json" }).as("getTemaKoder"); - cy.intercept("GET", "/api/countries*", { fixture: "getCountriesLangNb.json" }).as("getCountriesLangNb"); + cy.intercept('GET', '/mottaksadresse/submission', { fixture: 'mottakadresse.json' }).as('getMottakAdresse'); + cy.intercept('GET', /language\/submission?.*/, { fixture: 'globalTranslations.json' }).as('getTranslations'); + cy.intercept('GET', '/api/temakoder', { fixture: 'temakoder.json' }).as('getTemaKoder'); + cy.intercept('GET', '/api/countries*', { fixture: 'getCountriesLangNb.json' }).as('getCountriesLangNb'); }); - describe("Settings page", () => { + describe('Settings page', () => { beforeEach(() => { - cy.visit("forms/dif123456/settings"); - cy.wait("@getConfig"); - cy.wait("@getForm"); - cy.wait("@getPublishedForm"); - cy.wait("@getMottakAdresse"); - cy.wait("@getTemaKoder"); - cy.wait("@getCountriesLangNb"); - cy.wait("@getTranslations"); + cy.visit('forms/dif123456/settings'); + cy.wait('@getConfig'); + cy.wait('@getForm'); + cy.wait('@getPublishedForm'); + cy.wait('@getMottakAdresse'); + cy.wait('@getTemaKoder'); + cy.wait('@getCountriesLangNb'); + cy.wait('@getTranslations'); }); - it("Renders settings page without any diffs", () => { - cy.findByRole("heading", { name: "Skjema for testing av diff" }); - cy.findAllByText("Endring").should("have.length", 0); + it('Renders settings page without any diffs', () => { + cy.findByRole('heading', { name: 'Skjema for testing av diff' }); + cy.findAllByText('Endring').should('have.length', 0); }); - it("Renders tags when data is changed", () => { - cy.findByRole("textbox", { name: "Tittel" }).should("exist").type(" og sånt"); - cy.findAllByTestId("signatures") - .should("exist") + it('Renders tags when data is changed', () => { + cy.findByRole('textbox', { name: 'Tittel' }).should('exist').type(' og sånt'); + cy.findAllByTestId('signatures') + .should('exist') .within(() => { - cy.findByRole("textbox", { name: "Hvem skal signere?" }).should("exist").type("{selectall}Doktor"); + cy.findByRole('textbox', { name: 'Hvem skal signere?' }).should('exist').type('{selectall}Doktor'); }); - cy.findByRole("button", { name: "Legg til signatur" }).should("exist").click(); - cy.findAllByTestId("signatures") + cy.findByRole('button', { name: 'Legg til signatur' }).should('exist').click(); + cy.findAllByTestId('signatures') .eq(1) - .should("exist") + .should('exist') .within(() => { - cy.findByRole("textbox", { name: "Hvem skal signere?" }).should("exist").type("Advokat"); + cy.findByRole('textbox', { name: 'Hvem skal signere?' }).should('exist').type('Advokat'); }); - cy.findAllByText("Endring").should("have.length", 2); - cy.findAllByText("Ny").should("have.length", 1); + cy.findAllByText('Endring').should('have.length', 2); + cy.findAllByText('Ny').should('have.length', 1); }); }); - describe("Form builder page", () => { + describe('Form builder page', () => { beforeEach(() => { - cy.visit("forms/dif123456/edit"); - cy.wait("@getConfig"); - cy.wait("@getForm"); - cy.wait("@getPublishedForm"); - cy.wait("@getCountriesLangNb"); - cy.wait("@getTranslations"); + cy.visit('forms/dif123456/edit'); + cy.wait('@getConfig'); + cy.wait('@getForm'); + cy.wait('@getPublishedForm'); + cy.wait('@getCountriesLangNb'); + cy.wait('@getTranslations'); }); - describe("Tags", () => { + describe('Tags', () => { const diffSincePublishedVersion = { changes: 2, deletions: 1, }; - it("are visible for components that have changed", () => { - cy.findAllByText("Endring").should("have.length", diffSincePublishedVersion.changes); - cy.findAllByText("Slettede elementer").should("have.length", diffSincePublishedVersion.deletions); + it('are visible for components that have changed', () => { + cy.findAllByText('Endring').should('have.length', diffSincePublishedVersion.changes); + cy.findAllByText('Slettede elementer').should('have.length', diffSincePublishedVersion.deletions); }); - it("occur when component is deleted", () => { - cy.findByLabelText("Etternavn") - .should("exist") + it('occur when component is deleted', () => { + cy.findByLabelText('Etternavn') + .should('exist') .closest("[data-testid='builder-component']") - .within(clickBuilderComponentButton("Slett")); + .within(clickBuilderComponentButton('Slett')); - cy.findAllByText("Endring").should("have.length", diffSincePublishedVersion.changes); - cy.findAllByText("Slettede elementer").should("have.length", diffSincePublishedVersion.deletions + 1); + cy.findAllByText('Endring').should('have.length', diffSincePublishedVersion.changes); + cy.findAllByText('Slettede elementer').should('have.length', diffSincePublishedVersion.deletions + 1); }); it("are hidden when button 'Skjul endringer' is pressed", () => { - cy.findAllByText("Endring").should("have.length", diffSincePublishedVersion.changes); - cy.findAllByText("Slettede elementer").should("have.length", diffSincePublishedVersion.deletions); + cy.findAllByText('Endring').should('have.length', diffSincePublishedVersion.changes); + cy.findAllByText('Slettede elementer').should('have.length', diffSincePublishedVersion.deletions); - cy.findByRole("button", { name: "Skjul endringer" }).should("exist").click(); - cy.findAllByText("Endring").should("have.length", 0); - cy.findAllByText("Slettede elementer").should("have.length", 0); + cy.findByRole('button', { name: 'Skjul endringer' }).should('exist').click(); + cy.findAllByText('Endring').should('have.length', 0); + cy.findAllByText('Slettede elementer').should('have.length', 0); }); }); - describe("Edit component modal", () => { + describe('Edit component modal', () => { it("Shows changes for text component :: label 'Fornavn' -> 'Fornavn2'", () => { - cy.findByLabelText("Fornavn2") - .should("exist") + cy.findByLabelText('Fornavn2') + .should('exist') .closest("[data-testid='builder-component']") - .within(clickBuilderComponentButton("Rediger")); + .within(clickBuilderComponentButton('Rediger')); - cy.findByLabelText("Endringer") - .should("exist") + cy.findByLabelText('Endringer') + .should('exist') .within(() => { - cy.get("li").should("have.length", 1); - cy.get("li").eq(0).should("contain.text", "label: Fra 'Fornavn' til 'Fornavn2'"); + cy.get('li').should('have.length', 1); + cy.get('li').eq(0).should('contain.text', "label: Fra 'Fornavn' til 'Fornavn2'"); }); }); - it("Shows changes for skjemagruppe :: legend changed and component deleted", () => { - cy.findByText("Kontaktadresse2") - .should("exist") + it('Shows changes for skjemagruppe :: legend changed and component deleted', () => { + cy.findByText('Kontaktadresse2') + .should('exist') .closest("[data-testid='builder-component']") - .within(clickBuilderComponentButton("Rediger")); + .within(clickBuilderComponentButton('Rediger')); - cy.findByLabelText("Endringer") - .should("exist") + cy.findByLabelText('Endringer') + .should('exist') .within(() => { - cy.get("li").should("have.length", 1); - cy.get("li").eq(0).should("contain.text", "legend: Fra 'Kontaktadresse' til 'Kontaktadresse2'"); + cy.get('li').should('have.length', 1); + cy.get('li').eq(0).should('contain.text', "legend: Fra 'Kontaktadresse' til 'Kontaktadresse2'"); }); - cy.findByLabelText("Slettede elementer") - .should("exist") + cy.findByLabelText('Slettede elementer') + .should('exist') .within(() => { - cy.get("li").should("have.length", 2); - cy.get("li").eq(0).should("contain.text", "navDatepicker: "); - cy.get("li").eq(1).should("contain.text", "navDatepicker: "); + cy.get('li').should('have.length', 2); + cy.get('li').eq(0).should('contain.text', 'navDatepicker: '); + cy.get('li').eq(1).should('contain.text', 'navDatepicker: '); }); }); - it("Shows no changes for skjemagruppe", () => { - cy.findAllByText("Utenlandsk kontaktadresse") + it('Shows no changes for skjemagruppe', () => { + cy.findAllByText('Utenlandsk kontaktadresse') .first() - .should("exist") + .should('exist') .closest("[data-testid='builder-component']") - .within(clickBuilderComponentButton("Rediger")); + .within(clickBuilderComponentButton('Rediger')); - cy.findByLabelText("Endringer").should("not.exist"); - cy.findByLabelText("Slettede elementer").should("not.exist"); + cy.findByLabelText('Endringer').should('not.exist'); + cy.findByLabelText('Slettede elementer').should('not.exist'); }); }); }); diff --git a/packages/bygger/cypress/e2e/settings.spec.cy.ts b/packages/bygger/cypress/e2e/settings.spec.cy.ts index d6f8c3bdb..7273b2682 100644 --- a/packages/bygger/cypress/e2e/settings.spec.cy.ts +++ b/packages/bygger/cypress/e2e/settings.spec.cy.ts @@ -1,31 +1,33 @@ +import { expect } from 'chai'; + const _submitData = { - title: "Cypress test for settings page", - skjemanummer: "cypress-innstillinger", - tema: "BIL", - downloadPdfButtonText: "DownloadPDFBtnTest", - innsending: "PAPIR_OG_DIGITAL", - ettersending: "PAPIR_OG_DIGITAL", - descriptionOfSignatures: "Test Instructions", - signatureLabel: "Test account", - signatureDescription: "Instruction from test...", + title: 'Cypress test for settings page', + skjemanummer: 'cypress-innstillinger', + tema: 'BIL', + downloadPdfButtonText: 'DownloadPDFBtnTest', + innsending: 'PAPIR_OG_DIGITAL', + ettersending: 'PAPIR_OG_DIGITAL', + descriptionOfSignatures: 'Test Instructions', + signatureLabel: 'Test account', + signatureDescription: 'Instruction from test...', }; -describe("FormSettingsPage", () => { +describe('FormSettingsPage', () => { beforeEach(() => { - cy.intercept("GET", "/api/config", { fixture: "config.json" }).as("getConfig"); - cy.intercept("GET", "/form?*", { - fixture: "getForm.json", - }).as("getForm"); - cy.intercept("GET", "/api/published-forms/*", { statusCode: 404 }).as("getPublishedForm"); - cy.intercept("GET", "/mottaksadresse/submission", { fixture: "mottakadresse.json" }).as("getMottakAdresse"); - cy.intercept("GET", /language\/submission?.*/, { fixture: "globalTranslations.json" }).as("getTranslations"); - cy.intercept("GET", "/api/temakoder", { fixture: "temakoder.json" }).as("getTemaKoder"); - cy.intercept("GET", "/api/countries?*", { fixture: "getCountriesLangNb.json" }).as("getCountriesLangNb"); - cy.visit("forms/cypressinnstillinger/settings"); + cy.intercept('GET', '/api/config', { fixture: 'config.json' }).as('getConfig'); + cy.intercept('GET', '/form?*', { + fixture: 'getForm.json', + }).as('getForm'); + cy.intercept('GET', '/api/published-forms/*', { statusCode: 404 }).as('getPublishedForm'); + cy.intercept('GET', '/mottaksadresse/submission', { fixture: 'mottakadresse.json' }).as('getMottakAdresse'); + cy.intercept('GET', /language\/submission?.*/, { fixture: 'globalTranslations.json' }).as('getTranslations'); + cy.intercept('GET', '/api/temakoder', { fixture: 'temakoder.json' }).as('getTemaKoder'); + cy.intercept('GET', '/api/countries?*', { fixture: 'getCountriesLangNb.json' }).as('getCountriesLangNb'); + cy.visit('forms/cypressinnstillinger/settings'); }); - it("Fills all elements in settings page", () => { - cy.intercept("PUT", "form/*", (req) => { + it('Fills all elements in settings page', () => { + cy.intercept('PUT', 'form/*', (req) => { expect(req.body.properties.tema).to.include(_submitData.tema); expect(req.body.title).to.include(_submitData.title); expect(req.body.properties.skjemanummer).to.include(_submitData.skjemanummer); @@ -35,27 +37,34 @@ describe("FormSettingsPage", () => { expect(req.body.properties.signatures[0].label).to.include(_submitData.signatureLabel); expect(req.body.properties.signatures[0].description).to.include(_submitData.signatureDescription); req.reply(req.body); - }).as("compareRequestData"); - - cy.findByRole("textbox", { name: "Tittel" }).focus().clear().type(_submitData.title); - cy.findByRole("combobox", { name: "Tema" }).select(_submitData.tema); - cy.findByRole("textbox", { name: "Tekst på knapp for nedlasting av pdf" }) - .focus() - .clear() - .type(_submitData.downloadPdfButtonText); - cy.findByRole("combobox", { name: "Innsending" }).select(_submitData.innsending); - cy.findByRole("combobox", { name: "Ettersending" }).select(_submitData.ettersending); - cy.findByRole("textbox", { name: "Generelle instruksjoner (valgfritt)" }) - .focus() - .clear() - .type(_submitData.descriptionOfSignatures); - cy.findByRole("textbox", { name: "Hvem skal signere?" }).focus().clear().type(_submitData.signatureLabel); - cy.findByRole("textbox", { name: "Instruksjoner til den som signerer" }) - .focus() - .clear() - .type(_submitData.signatureDescription); - - cy.contains("Lagre").click(); - cy.get('[aria-live="polite"]').should("contain.text", `Lagret skjema ${_submitData.title}`); + }).as('compareRequestData'); + + cy.findByRole('textbox', { name: 'Tittel' }).focus(); + cy.findByRole('textbox', { name: 'Tittel' }).clear(); + cy.findByRole('textbox', { name: 'Tittel' }).type(_submitData.title); + + cy.findByRole('combobox', { name: 'Tema' }).select(_submitData.tema); + + cy.findByRole('textbox', { name: 'Tekst på knapp for nedlasting av pdf' }).focus(); + cy.findByRole('textbox', { name: 'Tekst på knapp for nedlasting av pdf' }).clear(); + cy.findByRole('textbox', { name: 'Tekst på knapp for nedlasting av pdf' }).type(_submitData.downloadPdfButtonText); + + cy.findByRole('combobox', { name: 'Innsending' }).select(_submitData.innsending); + cy.findByRole('combobox', { name: 'Ettersending' }).select(_submitData.ettersending); + + cy.findByRole('textbox', { name: 'Generelle instruksjoner (valgfritt)' }).focus(); + cy.findByRole('textbox', { name: 'Generelle instruksjoner (valgfritt)' }).clear(); + cy.findByRole('textbox', { name: 'Generelle instruksjoner (valgfritt)' }).type(_submitData.descriptionOfSignatures); + + cy.findByRole('textbox', { name: 'Hvem skal signere?' }).focus(); + cy.findByRole('textbox', { name: 'Hvem skal signere?' }).clear(); + cy.findByRole('textbox', { name: 'Hvem skal signere?' }).type(_submitData.signatureLabel); + + cy.findByRole('textbox', { name: 'Instruksjoner til den som signerer' }).focus(); + cy.findByRole('textbox', { name: 'Instruksjoner til den som signerer' }).clear(); + cy.findByRole('textbox', { name: 'Instruksjoner til den som signerer' }).type(_submitData.signatureDescription); + + cy.contains('Lagre').click(); + cy.get('[aria-live="polite"]').should('contain.text', `Lagret skjema ${_submitData.title}`); }); }); diff --git a/packages/bygger/cypress/support/commands.ts b/packages/bygger/cypress/support/commands.ts index 1ae1794c1..81670deeb 100644 --- a/packages/bygger/cypress/support/commands.ts +++ b/packages/bygger/cypress/support/commands.ts @@ -8,7 +8,7 @@ // commands please read more here: // https://on.cypress.io/custom-commands // *********************************************** -import "@testing-library/cypress/add-commands"; +import '@testing-library/cypress/add-commands'; // // -- This is a parent command -- diff --git a/packages/bygger/cypress/support/e2e.ts b/packages/bygger/cypress/support/e2e.ts index 6a173d6fc..598ab5f0d 100644 --- a/packages/bygger/cypress/support/e2e.ts +++ b/packages/bygger/cypress/support/e2e.ts @@ -14,7 +14,7 @@ // *********************************************************** // Import commands.js using ES2015 syntax: -import "./commands"; +import './commands'; // Alternatively you can use CommonJS syntax: // require('./commands') diff --git a/packages/bygger/index.html b/packages/bygger/index.html index a442264fd..c7fd5729a 100644 --- a/packages/bygger/index.html +++ b/packages/bygger/index.html @@ -1,27 +1,27 @@ - + - - - - - - - <% if (process.env.NODE_ENV !== 'development') { %> - - - <% } %> - - Skjemabygging - - - - - -
-
- - - + + + + + + + <% if (process.env.NODE_ENV !== 'development') { %> + + + <% } %> + + Skjemabygging + + + + + +
+
+ + + - - diff --git a/packages/bygger/scripts/import.js b/packages/bygger/scripts/import.js index 3f190de3b..9ff9f566d 100644 --- a/packages/bygger/scripts/import.js +++ b/packages/bygger/scripts/import.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -import fetch from "node-fetch"; +import fetch from 'node-fetch'; const [fromUrl, toApplication, jwtToken] = process.argv.slice(2); @@ -8,9 +8,9 @@ async function main() { const response = await fetch(fromUrl); const data = await response.json(); console.log(data); - const headers = { "x-jwt-token": jwtToken, "content-type": "application/json" }; - const postResponse = await fetch(toApplication + "/form", { - method: "POST", + const headers = { 'x-jwt-token': jwtToken, 'content-type': 'application/json' }; + const postResponse = await fetch(toApplication + '/form', { + method: 'POST', headers: headers, body: JSON.stringify(data), }); @@ -19,4 +19,4 @@ async function main() { } const promise = main(); -promise.then(() => console.log("done")); +promise.then(() => console.log('done')); diff --git a/packages/bygger/scripts/push_development_status_debug.js b/packages/bygger/scripts/push_development_status_debug.js index fddf09d0c..37b6ad9e8 100644 --- a/packages/bygger/scripts/push_development_status_debug.js +++ b/packages/bygger/scripts/push_development_status_debug.js @@ -1,15 +1,15 @@ -import Pusher from "pusher"; -import fs from "fs"; +import fs from 'fs'; +import Pusher from 'pusher'; function pusherAppValue(name) { return process.env[`PUSHER_APP_${name.toUpperCase()}`]; } const pusherApp = { - appId: pusherAppValue("id"), - key: pusherAppValue("key"), - secret: pusherAppValue("secret"), - cluster: pusherAppValue("cluster"), + appId: pusherAppValue('id'), + key: pusherAppValue('key'), + secret: pusherAppValue('secret'), + cluster: pusherAppValue('cluster'), }; const pusher = new Pusher({ @@ -17,7 +17,7 @@ const pusher = new Pusher({ useTLS: true, }); -const jsonString = fs.readFileSync(0, "utf-8"); +const jsonString = fs.readFileSync(0, 'utf-8'); const message = JSON.parse(jsonString); -pusher.trigger("deployment", "status", message); +pusher.trigger('deployment', 'status', message); diff --git a/packages/bygger/src/App.jsx b/packages/bygger/src/App.jsx index 9b95f01da..a860829a3 100644 --- a/packages/bygger/src/App.jsx +++ b/packages/bygger/src/App.jsx @@ -1,16 +1,16 @@ -import "@navikt/ds-css"; -import { NavFormioJs, Styles, makeStyles } from "@navikt/skjemadigitalisering-shared-components"; -import { useMemo } from "react"; -import AuthenticatedApp from "./AuthenticatedApp"; -import UnauthenticatedApp from "./UnauthenticatedApp"; -import { useAuth } from "./context/auth-context"; -import FeedbackProvider from "./context/notifications/FeedbackContext"; -import PusherNotificationsProvider from "./context/notifications/NotificationsContext"; +import '@navikt/ds-css'; +import { NavFormioJs, Styles, makeStyles } from '@navikt/skjemadigitalisering-shared-components'; +import { useMemo } from 'react'; +import AuthenticatedApp from './AuthenticatedApp'; +import UnauthenticatedApp from './UnauthenticatedApp'; +import { useAuth } from './context/auth-context'; +import FeedbackProvider from './context/notifications/FeedbackContext'; +import PusherNotificationsProvider from './context/notifications/NotificationsContext'; const useStyles = makeStyles({ - "@global": { - ".list-inline": { - listStyle: "none", + '@global': { + '.list-inline': { + listStyle: 'none', paddingLeft: 0, }, ...Styles.global, diff --git a/packages/bygger/src/App.test.jsx b/packages/bygger/src/App.test.jsx index d32ed1958..f50cac868 100644 --- a/packages/bygger/src/App.test.jsx +++ b/packages/bygger/src/App.test.jsx @@ -1,20 +1,20 @@ -import { AppConfigProvider, NavFormioJs } from "@navikt/skjemadigitalisering-shared-components"; -import { render, screen } from "@testing-library/react"; -import { MemoryRouter } from "react-router-dom"; -import createMockImplementation, { DEFAULT_PROJECT_URL } from "../test/backendMockImplementation"; -import featureToggles from "../test/featureToggles"; -import App from "./App"; -import { AuthContext } from "./context/auth-context"; +import { AppConfigProvider, NavFormioJs } from '@navikt/skjemadigitalisering-shared-components'; +import { render, screen } from '@testing-library/react'; +import { MemoryRouter } from 'react-router-dom'; +import createMockImplementation, { DEFAULT_PROJECT_URL } from '../test/backendMockImplementation'; +import featureToggles from '../test/featureToggles'; +import App from './App'; +import { AuthContext } from './context/auth-context'; const createFakeChannel = () => ({ bind: vi.fn(), unbind: vi.fn(), }); -describe("App", () => { +describe('App', () => { let formioFetch; beforeEach(() => { - formioFetch = vi.spyOn(NavFormioJs.Formio, "fetch"); + formioFetch = vi.spyOn(NavFormioJs.Formio, 'fetch'); formioFetch.mockImplementation(createMockImplementation()); }); @@ -24,7 +24,7 @@ describe("App", () => { const renderApp = (appConfigProps = {}) => { render( - + { ); }; - test("Show login form in development", async () => { + test('Show login form in development', async () => { renderApp({ config: { isDevelopment: true } }); - expect(await screen.findByLabelText("Email", { exact: false })).toBeTruthy(); - expect(await screen.findByLabelText("Password", { exact: false })).toBeTruthy(); + expect(await screen.findByLabelText('Email', { exact: false })).toBeTruthy(); + expect(await screen.findByLabelText('Password', { exact: false })).toBeTruthy(); }); - test("Do not show login form when not development", async () => { + test('Do not show login form when not development', async () => { renderApp({ config: { isDevelopment: false } }); - expect(await screen.findByText("Vennligst vent, du logges ut...")).toBeTruthy(); - expect(screen.queryByLabelText("Email", { exact: false })).toBeNull(); - expect(screen.queryByLabelText("Password", { exact: false })).toBeNull(); + expect(await screen.findByText('Vennligst vent, du logges ut...')).toBeTruthy(); + expect(screen.queryByLabelText('Email', { exact: false })).toBeNull(); + expect(screen.queryByLabelText('Password', { exact: false })).toBeNull(); }); }); diff --git a/packages/bygger/src/AuthenticatedApp.jsx b/packages/bygger/src/AuthenticatedApp.jsx index b63804e23..11ed63747 100644 --- a/packages/bygger/src/AuthenticatedApp.jsx +++ b/packages/bygger/src/AuthenticatedApp.jsx @@ -1,12 +1,11 @@ -import PropTypes from "prop-types"; -import React from "react"; -import { Navigate, Route, Routes } from "react-router-dom"; -import { FormsRouter } from "./Forms"; -import MigrationRouter from "./migration/MigrationRouter"; -import MottaksadresserPage from "./mottaksadresser/MottaksadresserPage"; -import ReportsPage from "./reports/ReportsPage"; -import TranslationsRouter from "./translations/TranslationsRouter"; -import BulkPublishPage from "./migration/BulkPublishPage"; +import PropTypes from 'prop-types'; +import { Navigate, Route, Routes } from 'react-router-dom'; +import { FormsRouter } from './Forms'; +import BulkPublishPage from './migration/BulkPublishPage'; +import MigrationRouter from './migration/MigrationRouter'; +import MottaksadresserPage from './mottaksadresser/MottaksadresserPage'; +import ReportsPage from './reports/ReportsPage'; +import TranslationsRouter from './translations/TranslationsRouter'; function AuthenticatedApp({ serverURL, formio }) { return ( diff --git a/packages/bygger/src/Forms/DefaultForm.js b/packages/bygger/src/Forms/DefaultForm.js index d3937deea..b44df6375 100644 --- a/packages/bygger/src/Forms/DefaultForm.js +++ b/packages/bygger/src/Forms/DefaultForm.js @@ -1,4 +1,4 @@ -import { FormBuilderSchemas } from "@navikt/skjemadigitalisering-shared-components"; +import { FormBuilderSchemas } from '@navikt/skjemadigitalisering-shared-components'; const { veiledningSchema, dineOpplysningerSchema, vedleggSchema } = FormBuilderSchemas; diff --git a/packages/bygger/src/Forms/EditFormPage.jsx b/packages/bygger/src/Forms/EditFormPage.jsx index 181a673bb..da03e403f 100644 --- a/packages/bygger/src/Forms/EditFormPage.jsx +++ b/packages/bygger/src/Forms/EditFormPage.jsx @@ -1,23 +1,23 @@ -import { BodyShort, Button, Heading } from "@navikt/ds-react"; -import { FormBuilderOptions, makeStyles } from "@navikt/skjemadigitalisering-shared-components"; -import { AppLayout } from "../components/AppLayout"; -import NavFormBuilder from "../components/NavFormBuilder"; -import PrimaryButtonWithSpinner from "../components/PrimaryButtonWithSpinner"; -import SkjemaVisningSelect from "../components/SkjemaVisningSelect"; -import UserFeedback from "../components/UserFeedback"; -import Column from "../components/layout/Column"; -import Row from "../components/layout/Row"; -import { useModal } from "../util/useModal"; -import PublishModalComponents from "./publish/PublishModalComponents"; -import FormStatusPanel from "./status/FormStatusPanel"; -import UnpublishButton from "./unpublish/UnpublishButton"; +import { BodyShort, Button, Heading } from '@navikt/ds-react'; +import { FormBuilderOptions, makeStyles } from '@navikt/skjemadigitalisering-shared-components'; +import { AppLayout } from '../components/AppLayout'; +import NavFormBuilder from '../components/NavFormBuilder'; +import PrimaryButtonWithSpinner from '../components/PrimaryButtonWithSpinner'; +import SkjemaVisningSelect from '../components/SkjemaVisningSelect'; +import UserFeedback from '../components/UserFeedback'; +import Column from '../components/layout/Column'; +import Row from '../components/layout/Row'; +import { useModal } from '../util/useModal'; +import PublishModalComponents from './publish/PublishModalComponents'; +import FormStatusPanel from './status/FormStatusPanel'; +import UnpublishButton from './unpublish/UnpublishButton'; const useStyles = makeStyles({ formBuilder: { - gridColumn: "1 / 3", + gridColumn: '1 / 3', }, centerColumn: { - gridColumn: "2 / 3", + gridColumn: '2 / 3', }, }); diff --git a/packages/bygger/src/Forms/FormPage.jsx b/packages/bygger/src/Forms/FormPage.jsx index 117779f0d..563ae8e1f 100644 --- a/packages/bygger/src/Forms/FormPage.jsx +++ b/packages/bygger/src/Forms/FormPage.jsx @@ -1,19 +1,19 @@ -import { LoadingComponent, useAppConfig } from "@navikt/skjemadigitalisering-shared-components"; -import React, { useCallback, useEffect, useReducer } from "react"; -import { Navigate, Route, Routes, useParams } from "react-router-dom"; -import I18nStateProvider from "../context/i18n/I18nContext"; -import { loadPublishedForm } from "./diffing/publishedForm"; -import { EditFormPage } from "./EditFormPage"; -import formPageReducer from "./formPageReducer"; -import { FormSettingsPage } from "./FormSettingsPage"; -import { TestFormPage } from "./TestFormPage"; +import { LoadingComponent, useAppConfig } from '@navikt/skjemadigitalisering-shared-components'; +import { useCallback, useEffect, useReducer } from 'react'; +import { Navigate, Route, Routes, useParams } from 'react-router-dom'; +import I18nStateProvider from '../context/i18n/I18nContext'; +import { EditFormPage } from './EditFormPage'; +import { FormSettingsPage } from './FormSettingsPage'; +import { TestFormPage } from './TestFormPage'; +import { loadPublishedForm } from './diffing/publishedForm'; +import formPageReducer from './formPageReducer'; export const FormPage = ({ loadForm, loadTranslations, onSave, onPublish, onUnpublish }) => { const { featureToggles, diffOn } = useAppConfig(); const { formPath } = useParams(); const [state, dispatch] = useReducer( formPageReducer, - { status: "LOADING", hasUnsavedChanges: false }, + { status: 'LOADING', hasUnsavedChanges: false }, (state) => state, ); const loadTranslationsForFormPath = useCallback( @@ -26,29 +26,29 @@ export const FormPage = ({ loadForm, loadTranslations, onSave, onPublish, onUnpu .then((form) => { if (featureToggles.enableDiff) { loadPublishedForm(formPath) - .then((publishedForm) => dispatch({ type: "form-loaded", form, publishedForm })) + .then((publishedForm) => dispatch({ type: 'form-loaded', form, publishedForm })) .catch(() => { - console.debug("Failed to load published form"); - dispatch({ type: "form-loaded", form }); + console.debug('Failed to load published form'); + dispatch({ type: 'form-loaded', form }); }); } else { - dispatch({ type: "form-loaded", form }); + dispatch({ type: 'form-loaded', form }); } }) .catch((e) => { console.log(e); - dispatch({ type: "form-not-found" }); + dispatch({ type: 'form-not-found' }); }); }, [loadForm, formPath, featureToggles.enableDiff]); const onChange = (changedForm) => { - dispatch({ type: "form-changed", form: changedForm }); + dispatch({ type: 'form-changed', form: changedForm }); }; const saveFormAndResetIsUnsavedChanges = async (form) => { const savedForm = await onSave(form); if (!savedForm.error) { - dispatch({ type: "form-saved", form: savedForm }); + dispatch({ type: 'form-saved', form: savedForm }); return savedForm; } return form; @@ -57,28 +57,28 @@ export const FormPage = ({ loadForm, loadTranslations, onSave, onPublish, onUnpu const publishForm = async (form, translations) => { const savedForm = await onPublish(form, translations); await loadPublishedForm(formPath) - .then((publishedForm) => dispatch({ type: "form-saved", form: savedForm, publishedForm })) + .then((publishedForm) => dispatch({ type: 'form-saved', form: savedForm, publishedForm })) .catch(() => { - console.debug("Publish completed: Failed to load published form"); - dispatch({ type: "form-saved", form: savedForm }); + console.debug('Publish completed: Failed to load published form'); + dispatch({ type: 'form-saved', form: savedForm }); }); }; const unpublishForm = async (form) => { const savedForm = await onUnpublish(form); await loadPublishedForm(formPath) - .then((publishedForm) => dispatch({ type: "form-saved", form: savedForm, publishedForm })) + .then((publishedForm) => dispatch({ type: 'form-saved', form: savedForm, publishedForm })) .catch(() => { - console.debug("Unpublish completed: Failed to load published form"); - dispatch({ type: "form-saved", form: savedForm }); + console.debug('Unpublish completed: Failed to load published form'); + dispatch({ type: 'form-saved', form: savedForm }); }); }; - if (state.status === "LOADING") { + if (state.status === 'LOADING') { return ; } - if (state.status === "FORM NOT FOUND" || !state.form) { + if (state.status === 'FORM NOT FOUND' || !state.form) { return

Vi fant ikke dette skjemaet...

; } @@ -86,7 +86,7 @@ export const FormPage = ({ loadForm, loadTranslations, onSave, onPublish, onUnpu } /> - } /> + } /> } /> - } /> + } /> ); diff --git a/packages/bygger/src/Forms/FormSettingsPage.jsx b/packages/bygger/src/Forms/FormSettingsPage.jsx index ef4d3234a..02cd411aa 100644 --- a/packages/bygger/src/Forms/FormSettingsPage.jsx +++ b/packages/bygger/src/Forms/FormSettingsPage.jsx @@ -1,21 +1,21 @@ -import { Button, Heading } from "@navikt/ds-react"; -import { makeStyles } from "@navikt/skjemadigitalisering-shared-components"; -import { useState } from "react"; -import { AppLayout } from "../components/AppLayout"; -import { FormMetadataEditor } from "../components/FormMetaDataEditor/FormMetadataEditor"; -import { isFormMetadataValid, validateFormMetadata } from "../components/FormMetaDataEditor/utils"; -import PrimaryButtonWithSpinner from "../components/PrimaryButtonWithSpinner"; -import UserFeedback from "../components/UserFeedback"; -import Column from "../components/layout/Column"; -import Row from "../components/layout/Row"; -import { useModal } from "../util/useModal"; -import PublishModalComponents from "./publish/PublishModalComponents"; -import FormStatusPanel from "./status/FormStatusPanel"; -import UnpublishButton from "./unpublish/UnpublishButton"; +import { Button, Heading } from '@navikt/ds-react'; +import { makeStyles } from '@navikt/skjemadigitalisering-shared-components'; +import { useState } from 'react'; +import { AppLayout } from '../components/AppLayout'; +import { FormMetadataEditor } from '../components/FormMetaDataEditor/FormMetadataEditor'; +import { isFormMetadataValid, validateFormMetadata } from '../components/FormMetaDataEditor/utils'; +import PrimaryButtonWithSpinner from '../components/PrimaryButtonWithSpinner'; +import UserFeedback from '../components/UserFeedback'; +import Column from '../components/layout/Column'; +import Row from '../components/layout/Row'; +import { useModal } from '../util/useModal'; +import PublishModalComponents from './publish/PublishModalComponents'; +import FormStatusPanel from './status/FormStatusPanel'; +import UnpublishButton from './unpublish/UnpublishButton'; const useStyles = makeStyles({ mainCol: { - gridColumn: "2 / 3", + gridColumn: '2 / 3', }, }); @@ -26,7 +26,7 @@ export function FormSettingsPage({ form, publishedForm, onSave, onChange, onPubl const [errors, setErrors] = useState({}); validateAndSave = async (form) => { - const updatedErrors = validateFormMetadata(form, "edit"); + const updatedErrors = validateFormMetadata(form, 'edit'); if (isFormMetadataValid(updatedErrors)) { setErrors({}); return await onSave(form); @@ -38,7 +38,7 @@ export function FormSettingsPage({ form, publishedForm, onSave, onChange, onPubl return ( { - if (direction === "ascending") return ; - if (direction === "descending") return ; + if (direction === 'ascending') return ; + if (direction === 'descending') return ; return ; }; @@ -60,13 +60,13 @@ const FormsList = ({ formMetadataList, children }: FormsListProps) => { const [sortBy, setSortBy] = useState(); const sortedFormsList = useMemo(() => { - const sortedByModified = sortFormsByProperty(formMetadataList, "modified", "descending"); + const sortedByModified = sortFormsByProperty(formMetadataList, 'modified', 'descending'); switch (sortBy) { - case "formTitle": - return sortFormsByProperty(sortedByModified, "title", sortDirection); - case "formNumber": + case 'formTitle': + return sortFormsByProperty(sortedByModified, 'title', sortDirection); + case 'formNumber': return sortByFormNumber(sortedByModified, sortDirection); - case "formStatus": + case 'formStatus': return sortByStatus(sortedByModified, sortDirection); default: return sortedByModified; @@ -74,15 +74,15 @@ const FormsList = ({ formMetadataList, children }: FormsListProps) => { }, [formMetadataList, sortBy, sortDirection]); function nextSortDirection(currentSortDirection?: SortDirection): SortDirection | undefined { - if (!currentSortDirection) return "ascending"; - if (currentSortDirection === "ascending") return "descending"; + if (!currentSortDirection) return 'ascending'; + if (currentSortDirection === 'ascending') return 'descending'; return undefined; } function toggleSortState(selectedProperty: SortByProperty) { if (sortBy !== selectedProperty) { setSortBy(selectedProperty); - setSortDirection("ascending"); + setSortDirection('ascending'); } else { const newSortDirection = nextSortDirection(sortDirection); setSortDirection(newSortDirection); @@ -93,23 +93,23 @@ const FormsList = ({ formMetadataList, children }: FormsListProps) => { return (
  • -
    toggleSortState("formNumber")}> +
    toggleSortState('formNumber')}> Skjemanr. - +
    -
    toggleSortState("formTitle")}> +
    toggleSortState('formTitle')}> Skjematittel - +
    -
    toggleSortState("formStatus")}> +
    toggleSortState('formStatus')}> Status - +
  • {sortedFormsList.map(children)} @@ -119,21 +119,21 @@ const FormsList = ({ formMetadataList, children }: FormsListProps) => { const useFormsListPageStyles = makeStyles({ root: { - maxWidth: "50rem", - margin: "0 auto 2rem", + maxWidth: '50rem', + margin: '0 auto 2rem', }, listItem: { - padding: "0.3rem 0.5rem", - display: "grid", - gridTemplateColumns: "minmax(5rem,10rem) auto 8rem", - width: "auto", - "&:nth-child(odd)": { - backgroundColor: "#ddd", + padding: '0.3rem 0.5rem', + display: 'grid', + gridTemplateColumns: 'minmax(5rem,10rem) auto 8rem', + width: 'auto', + '&:nth-child(odd)': { + backgroundColor: '#ddd', }, }, centerColumn: { - gridColumn: "2 / 3", - width: "max-content", + gridColumn: '2 / 3', + width: 'max-content', }, }); @@ -144,35 +144,35 @@ interface FormsListPageProps { const FormsListPage = ({ loadFormsList }: FormsListPageProps) => { const navigate = useNavigate(); const classes = useFormsListPageStyles(); - const [status, setStatus] = useState("LOADING"); + const [status, setStatus] = useState('LOADING'); const [forms, setForms] = useState(); useEffect(() => { loadFormsList() .then((forms) => { setForms(forms); - setStatus("FINISHED LOADING"); + setStatus('FINISHED LOADING'); }) .catch((e) => { console.log(e); - setStatus("FORMS NOT FOUND"); + setStatus('FORMS NOT FOUND'); }); }, [loadFormsList]); - if (status === "LOADING") { + if (status === 'LOADING') { return ; } - if (status === "FORMS NOT FOUND" || !forms) { + if (status === 'FORMS NOT FOUND' || !forms) { return

    Finner ingen skjemaer...

    ; } - const onNew = () => navigate("/forms/new"); + const onNew = () => navigate('/forms/new'); return ( { ); }; -export { FormsListPage, FormsList }; +export { FormsList, FormsListPage }; diff --git a/packages/bygger/src/Forms/NewFormPage.test.tsx b/packages/bygger/src/Forms/NewFormPage.test.tsx index 437e44ae4..a1b928eba 100644 --- a/packages/bygger/src/Forms/NewFormPage.test.tsx +++ b/packages/bygger/src/Forms/NewFormPage.test.tsx @@ -1,35 +1,35 @@ -import { AppConfigProvider } from "@navikt/skjemadigitalisering-shared-components"; -import { NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; -import { render, screen, waitFor } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import { MemoryRouter } from "react-router-dom"; -import mockMottaksadresser from "../../example_data/mottaksadresser.json"; -import featureToggles from "../../test/featureToggles"; -import FeedbackProvider from "../context/notifications/FeedbackContext"; -import NewFormPage from "./NewFormPage"; +import { AppConfigProvider } from '@navikt/skjemadigitalisering-shared-components'; +import { NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { MemoryRouter } from 'react-router-dom'; +import mockMottaksadresser from '../../example_data/mottaksadresser.json'; +import featureToggles from '../../test/featureToggles'; +import FeedbackProvider from '../context/notifications/FeedbackContext'; +import NewFormPage from './NewFormPage'; const RESPONSE_HEADERS = { headers: { - "content-type": "application/json", + 'content-type': 'application/json', }, }; -const mockTemaKoder = { ABC: "Tema 1", XYZ: "Tema 3", DEF: "Tema 2" }; +const mockTemaKoder = { ABC: 'Tema 1', XYZ: 'Tema 3', DEF: 'Tema 2' }; -describe("NewFormPage", () => { +describe('NewFormPage', () => { beforeEach(() => { fetchMock.mockImplementation((url) => { const stringUrl = url as string; - if (stringUrl.endsWith("/mottaksadresse/submission")) { + if (stringUrl.endsWith('/mottaksadresse/submission')) { return Promise.resolve(new Response(JSON.stringify(mockMottaksadresser), RESPONSE_HEADERS)); } - if (stringUrl.endsWith("/temakoder")) { + if (stringUrl.endsWith('/temakoder')) { return Promise.resolve(new Response(JSON.stringify(mockTemaKoder), RESPONSE_HEADERS)); } throw new Error(`Manglende testoppsett: Ukjent url ${url}`); }); }); - it("should create a new form with correct path, title and name", async () => { + it('should create a new form with correct path, title and name', async () => { const saveForm = vi.fn(() => Promise.resolve(new Response(JSON.stringify({})))); render( @@ -38,31 +38,31 @@ describe("NewFormPage", () => { , ); - await waitFor(() => screen.getByText("Opprett nytt skjema")); + await waitFor(() => screen.getByText('Opprett nytt skjema')); - await userEvent.type(screen.getByLabelText("Skjemanummer"), "NAV 10-20.30 "); - await userEvent.type(screen.getByLabelText("Tittel"), "Et testskjema"); - await userEvent.selectOptions(screen.getByLabelText("Tema"), "ABC"); - await userEvent.click(screen.getByRole("button", { name: "Opprett" })); + await userEvent.type(screen.getByLabelText('Skjemanummer'), 'NAV 10-20.30 '); + await userEvent.type(screen.getByLabelText('Tittel'), 'Et testskjema'); + await userEvent.selectOptions(screen.getByLabelText('Tema'), 'ABC'); + await userEvent.click(screen.getByRole('button', { name: 'Opprett' })); expect(saveForm).toHaveBeenCalledTimes(1); // @ts-ignore const savedForm = saveForm.mock.calls[0][0] as NavFormType; expect(savedForm).toMatchObject({ - type: "form", - path: "nav102030", - display: "wizard", - name: "nav102030", - title: "Et testskjema", - tags: ["nav-skjema", ""], + type: 'form', + path: 'nav102030', + display: 'wizard', + name: 'nav102030', + title: 'Et testskjema', + tags: ['nav-skjema', ''], properties: { - skjemanummer: "NAV 10-20.30", - tema: "ABC", + skjemanummer: 'NAV 10-20.30', + tema: 'ABC', }, }); }); - it("should handle exception from saveForm, with message to user", async () => { - const saveForm = vi.fn(() => Promise.reject(new Error("Form.io feil"))); + it('should handle exception from saveForm, with message to user', async () => { + const saveForm = vi.fn(() => Promise.reject(new Error('Form.io feil'))); console.error = vi.fn(); render( @@ -73,17 +73,17 @@ describe("NewFormPage", () => { , ); - await screen.findByText("Opprett nytt skjema"); + await screen.findByText('Opprett nytt skjema'); - await userEvent.type(screen.getByLabelText("Skjemanummer"), "NAV 10-20.30 "); - await userEvent.type(screen.getByLabelText("Tittel"), "Et testskjema"); - await userEvent.selectOptions(screen.getByLabelText("Tema"), "ABC"); - await userEvent.click(screen.getByRole("button", { name: "Opprett" })); + await userEvent.type(screen.getByLabelText('Skjemanummer'), 'NAV 10-20.30 '); + await userEvent.type(screen.getByLabelText('Tittel'), 'Et testskjema'); + await userEvent.selectOptions(screen.getByLabelText('Tema'), 'ABC'); + await userEvent.click(screen.getByRole('button', { name: 'Opprett' })); expect(saveForm).toHaveBeenCalledTimes(1); await waitFor(() => expect(console.error).toHaveBeenCalledTimes(1)); - expect(await screen.findByText("Det valgte skjema-nummeret er allerede i bruk.")).toBeInTheDocument(); + expect(await screen.findByText('Det valgte skjema-nummeret er allerede i bruk.')).toBeInTheDocument(); }); }); diff --git a/packages/bygger/src/Forms/NewFormPage.tsx b/packages/bygger/src/Forms/NewFormPage.tsx index f8f8ad7f2..df9caacb7 100644 --- a/packages/bygger/src/Forms/NewFormPage.tsx +++ b/packages/bygger/src/Forms/NewFormPage.tsx @@ -1,22 +1,22 @@ -import { Button, Heading } from "@navikt/ds-react"; -import { makeStyles } from "@navikt/skjemadigitalisering-shared-components"; -import { Component, NavFormType, navFormUtils, stringUtils } from "@navikt/skjemadigitalisering-shared-domain"; -import cloneDeep from "lodash.clonedeep"; -import React, { useState } from "react"; -import { useNavigate } from "react-router-dom"; -import { v4 as uuidv4 } from "uuid"; -import { AppLayout } from "../components/AppLayout"; -import { CreationFormMetadataEditor } from "../components/FormMetaDataEditor/FormMetadataEditor"; -import { isFormMetadataValid, validateFormMetadata } from "../components/FormMetaDataEditor/utils"; -import UserFeedback from "../components/UserFeedback"; -import Column from "../components/layout/Column"; -import Row from "../components/layout/Row"; -import { useFeedbackEmit } from "../context/notifications/FeedbackContext"; -import { defaultFormFields } from "./DefaultForm"; +import { Button, Heading } from '@navikt/ds-react'; +import { makeStyles } from '@navikt/skjemadigitalisering-shared-components'; +import { Component, NavFormType, navFormUtils, stringUtils } from '@navikt/skjemadigitalisering-shared-domain'; +import cloneDeep from 'lodash.clonedeep'; +import React, { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { v4 as uuidv4 } from 'uuid'; +import { AppLayout } from '../components/AppLayout'; +import { CreationFormMetadataEditor } from '../components/FormMetaDataEditor/FormMetadataEditor'; +import { isFormMetadataValid, validateFormMetadata } from '../components/FormMetaDataEditor/utils'; +import UserFeedback from '../components/UserFeedback'; +import Column from '../components/layout/Column'; +import Row from '../components/layout/Row'; +import { useFeedbackEmit } from '../context/notifications/FeedbackContext'; +import { defaultFormFields } from './DefaultForm'; const useStyles = makeStyles({ centerColumn: { - gridColumn: "2 / 3", + gridColumn: '2 / 3', }, }); @@ -34,18 +34,18 @@ const NewFormPage: React.FC = ({ formio }): React.ReactElement => { const styles = useStyles(); const [state, setState] = useState({ form: { - tags: ["nav-skjema", ""], - type: "form", - display: "wizard", - name: "", - title: "", - path: "", + tags: ['nav-skjema', ''], + type: 'form', + display: 'wizard', + name: '', + title: '', + path: '', properties: { - skjemanummer: "", - tema: "", - innsending: "PAPIR_OG_DIGITAL", - ettersending: "PAPIR_OG_DIGITAL", - signatures: [{ label: "", description: "", key: uuidv4() }], + skjemanummer: '', + tema: '', + innsending: 'PAPIR_OG_DIGITAL', + ettersending: 'PAPIR_OG_DIGITAL', + signatures: [{ label: '', description: '', key: uuidv4() }], }, components: defaultFormFields() as unknown as Component[], }, @@ -64,7 +64,7 @@ const NewFormPage: React.FC = ({ formio }): React.ReactElement => { }); }; const validateAndSave = async (form) => { - const updatedErrors = validateFormMetadata(form, "create"); + const updatedErrors = validateFormMetadata(form, 'create'); const trimmedFormNumber = state.form.properties.skjemanummer.trim(); if (isFormMetadataValid(updatedErrors)) { setErrors({}); @@ -75,7 +75,7 @@ const NewFormPage: React.FC = ({ formio }): React.ReactElement => { navigate(`/forms/${form.path}/edit`); }) .catch((e) => { - feedbackEmit.error("Det valgte skjema-nummeret er allerede i bruk."); + feedbackEmit.error('Det valgte skjema-nummeret er allerede i bruk.'); console.error(e); }); } else { @@ -88,7 +88,7 @@ const NewFormPage: React.FC = ({ formio }): React.ReactElement => { }; return ( - + diff --git a/packages/bygger/src/Forms/PageWrapper.tsx b/packages/bygger/src/Forms/PageWrapper.tsx index 299e9aed9..a8d25d629 100644 --- a/packages/bygger/src/Forms/PageWrapper.tsx +++ b/packages/bygger/src/Forms/PageWrapper.tsx @@ -1,9 +1,9 @@ -import { makeStyles } from "@navikt/skjemadigitalisering-shared-components"; +import { makeStyles } from '@navikt/skjemadigitalisering-shared-components'; const useStyles = makeStyles({ wrapper: { - margin: "0 auto", - padding: "2rem 2rem 0", + margin: '0 auto', + padding: '2rem 2rem 0', }, }); diff --git a/packages/bygger/src/Forms/TestFormPage.jsx b/packages/bygger/src/Forms/TestFormPage.jsx index b4c43560e..d3610bf69 100644 --- a/packages/bygger/src/Forms/TestFormPage.jsx +++ b/packages/bygger/src/Forms/TestFormPage.jsx @@ -1,15 +1,15 @@ -import { FyllUtRouter, useAppConfig } from "@navikt/skjemadigitalisering-shared-components"; -import { AppLayout } from "../components/AppLayout"; -import { useI18nState } from "../context/i18n/I18nContext"; +import { FyllUtRouter, useAppConfig } from '@navikt/skjemadigitalisering-shared-components'; +import { AppLayout } from '../components/AppLayout'; +import { useI18nState } from '../context/i18n/I18nContext'; -export function TestFormPage({ form, visSkjemaMeny }) { +export function TestFormPage({ form }) { const { featureToggles } = useAppConfig(); const { translationsForNavForm } = useI18nState(); return ( { const formPageReducer = (state: ReducerState, action: ReducerActionType) => { const formClone = cloneDeep(action.form); switch (action.type) { - case "form-loaded": - case "form-saved": + case 'form-loaded': + case 'form-saved': return { - status: "FINISHED LOADING", + status: 'FINISHED LOADING', dbForm: formClone, form: formClone, publishedForm: action.publishedForm || state.publishedForm, hasUnsavedChanges: false, }; - case "form-changed": + case 'form-changed': return { ...state, dbForm: state.dbForm, form: formClone, hasUnsavedChanges: isDifferent(state.dbForm, formClone), }; - case "form-not-found": + case 'form-not-found': return { - status: "FORM NOT FOUND", + status: 'FORM NOT FOUND', hasUnsavedChanges: false, }; default: { diff --git a/packages/bygger/src/Forms/formsListUtils.test.ts b/packages/bygger/src/Forms/formsListUtils.test.ts index 7d582f296..f4a4f4809 100644 --- a/packages/bygger/src/Forms/formsListUtils.test.ts +++ b/packages/bygger/src/Forms/formsListUtils.test.ts @@ -1,118 +1,118 @@ -import moment from "moment"; -import { FormMetadata, sortByFormNumber, sortByStatus, sortFormsByProperty } from "./formsListUtils"; +import moment from 'moment'; +import { FormMetadata, sortByFormNumber, sortByStatus, sortFormsByProperty } from './formsListUtils'; const baseMoment = moment().toISOString(); -const earlier = (base, days) => moment(base).subtract(days, "day").toISOString(); -const later = (base, days) => moment(base).add(days, "day").toISOString(); +const earlier = (base, days) => moment(base).subtract(days, 'day').toISOString(); +const later = (base, days) => moment(base).add(days, 'day').toISOString(); const createFormMetadata = (properties: Partial): FormMetadata => ({ - _id: "id", + _id: 'id', modified: baseMoment, - title: "AAA", - skjemanummer: "000", - status: "UNKNOWN", + title: 'AAA', + skjemanummer: '000', + status: 'UNKNOWN', ...properties, }) as FormMetadata; -describe("formsListUtils", () => { - describe("sortFormsByProperty", () => { - describe("title (string)", () => { - const abc = createFormMetadata({ title: "abc" }); - const ABC = createFormMetadata({ title: "ABC" }); - const number123 = createFormMetadata({ title: "123" }); - const A1 = createFormMetadata({ title: "A1" }); - const AAsta = createFormMetadata({ title: "Åsta" }); - const aBC = createFormMetadata({ title: "aBC" }); - const emptyString = createFormMetadata({ title: "" }); +describe('formsListUtils', () => { + describe('sortFormsByProperty', () => { + describe('title (string)', () => { + const abc = createFormMetadata({ title: 'abc' }); + const ABC = createFormMetadata({ title: 'ABC' }); + const number123 = createFormMetadata({ title: '123' }); + const A1 = createFormMetadata({ title: 'A1' }); + const AAsta = createFormMetadata({ title: 'Åsta' }); + const aBC = createFormMetadata({ title: 'aBC' }); + const emptyString = createFormMetadata({ title: '' }); const list = [aBC, ABC, AAsta, number123, emptyString, abc, A1]; - it("sorts in ascending order", () => { - const sorted = sortFormsByProperty(list, "title", "ascending"); + it('sorts in ascending order', () => { + const sorted = sortFormsByProperty(list, 'title', 'ascending'); expect(sorted).toHaveLength(7); expect(sorted).toStrictEqual([emptyString, number123, A1, ABC, aBC, abc, AAsta]); }); - it("sorts modified (date) in descending order", () => { - const sorted = sortFormsByProperty(list, "modified", "descending"); + it('sorts modified (date) in descending order', () => { + const sorted = sortFormsByProperty(list, 'modified', 'descending'); expect(sorted).toHaveLength(7); expect(sorted).toStrictEqual([AAsta, abc, aBC, ABC, A1, number123, emptyString]); }); }); - describe("modified (date)", () => { - const earliest = createFormMetadata({ title: "Earliest", modified: earlier(baseMoment, "4") }); - const early = createFormMetadata({ title: "Early", modified: earlier(baseMoment, "2") }); - const middle = createFormMetadata({ title: "Middle", modified: baseMoment }); - const late = createFormMetadata({ title: "Late", modified: later(baseMoment, "2") }); - const latest = createFormMetadata({ title: "Latest", modified: later(baseMoment, "4") }); - const noDate = createFormMetadata({ title: "No modified", modified: undefined }); + describe('modified (date)', () => { + const earliest = createFormMetadata({ title: 'Earliest', modified: earlier(baseMoment, '4') }); + const early = createFormMetadata({ title: 'Early', modified: earlier(baseMoment, '2') }); + const middle = createFormMetadata({ title: 'Middle', modified: baseMoment }); + const late = createFormMetadata({ title: 'Late', modified: later(baseMoment, '2') }); + const latest = createFormMetadata({ title: 'Latest', modified: later(baseMoment, '4') }); + const noDate = createFormMetadata({ title: 'No modified', modified: undefined }); const list = [early, noDate, latest, late, earliest, middle]; - it("sorts in ascending order", () => { - const sorted = sortFormsByProperty(list, "modified", "ascending"); + it('sorts in ascending order', () => { + const sorted = sortFormsByProperty(list, 'modified', 'ascending'); expect(sorted).toHaveLength(6); expect(sorted).toStrictEqual([noDate, earliest, early, middle, late, latest]); }); - it("sorts modified (date) in descending order", () => { - const sorted = sortFormsByProperty(list, "modified", "descending"); + it('sorts modified (date) in descending order', () => { + const sorted = sortFormsByProperty(list, 'modified', 'descending'); expect(sorted).toHaveLength(6); expect(sorted).toStrictEqual([latest, late, middle, early, earliest, noDate]); }); }); }); - describe("sortByFormNumber", () => { - const nav01 = createFormMetadata({ skjemanummer: "NAV 01-00.00" }); - const nav02 = createFormMetadata({ skjemanummer: "NAV 02-00.00" }); - const nav03 = createFormMetadata({ skjemanummer: "NAV 03-00.00" }); - const noneStandard01 = createFormMetadata({ skjemanummer: "ABC 02-00.00" }); - const noneStandard02 = createFormMetadata({ skjemanummer: "NAV 02.00-00" }); + describe('sortByFormNumber', () => { + const nav01 = createFormMetadata({ skjemanummer: 'NAV 01-00.00' }); + const nav02 = createFormMetadata({ skjemanummer: 'NAV 02-00.00' }); + const nav03 = createFormMetadata({ skjemanummer: 'NAV 03-00.00' }); + const noneStandard01 = createFormMetadata({ skjemanummer: 'ABC 02-00.00' }); + const noneStandard02 = createFormMetadata({ skjemanummer: 'NAV 02.00-00' }); const list = [nav02, noneStandard02, nav03, noneStandard01, nav01]; - it("places standard NAV form numbers first on ascending sort", () => { - const sorted = sortByFormNumber(list, "ascending"); + it('places standard NAV form numbers first on ascending sort', () => { + const sorted = sortByFormNumber(list, 'ascending'); expect(sorted).toHaveLength(5); expect(sorted).toStrictEqual([nav01, nav02, nav03, noneStandard01, noneStandard02]); }); - it("places standard NAV form numbers last on descending sort", () => { - const sorted = sortByFormNumber(list, "descending"); + it('places standard NAV form numbers last on descending sort', () => { + const sorted = sortByFormNumber(list, 'descending'); expect(sorted).toHaveLength(5); expect(sorted).toStrictEqual([noneStandard02, noneStandard01, nav03, nav02, nav01]); }); }); - describe("sortByStatus", () => { - const draft = createFormMetadata({ status: "DRAFT" }); - const published = createFormMetadata({ status: "PUBLISHED" }); - const unpublished = createFormMetadata({ status: "UNPUBLISHED" }); - const pending = createFormMetadata({ status: "PENDING" }); - const unknown = createFormMetadata({ status: "UNKNOWN" }); - const testform = createFormMetadata({ status: "TESTFORM" }); + describe('sortByStatus', () => { + const draft = createFormMetadata({ status: 'DRAFT' }); + const published = createFormMetadata({ status: 'PUBLISHED' }); + const unpublished = createFormMetadata({ status: 'UNPUBLISHED' }); + const pending = createFormMetadata({ status: 'PENDING' }); + const unknown = createFormMetadata({ status: 'UNKNOWN' }); + const testform = createFormMetadata({ status: 'TESTFORM' }); const list = [draft, published, pending, testform, unpublished]; const listWithUnknown = [pending, unknown, published, draft, unpublished, testform]; - it("sorts the list by status in fixed ascending order", () => { - const sorted = sortByStatus(list, "ascending"); + it('sorts the list by status in fixed ascending order', () => { + const sorted = sortByStatus(list, 'ascending'); expect(sorted).toStrictEqual([published, pending, draft, unpublished, testform]); }); - it("sorts the list by status in fixed descending order", () => { - const sorted = sortByStatus(list, "descending"); + it('sorts the list by status in fixed descending order', () => { + const sorted = sortByStatus(list, 'descending'); expect(sorted).toStrictEqual([testform, unpublished, draft, pending, published]); }); - it("adds items with status UNKNOWN to the end of list when sorting in ascending order", () => { - const sorted = sortByStatus(listWithUnknown, "ascending"); + it('adds items with status UNKNOWN to the end of list when sorting in ascending order', () => { + const sorted = sortByStatus(listWithUnknown, 'ascending'); expect(sorted).toHaveLength(6); - expect(sorted[5].status).toBe("UNKNOWN"); + expect(sorted[5].status).toBe('UNKNOWN'); }); - it("adds items with status UNKNOWN to the end of list when sorting in descending order", () => { - const sorted = sortByStatus(listWithUnknown, "descending"); + it('adds items with status UNKNOWN to the end of list when sorting in descending order', () => { + const sorted = sortByStatus(listWithUnknown, 'descending'); expect(sorted).toHaveLength(6); - expect(sorted[5].status).toBe("UNKNOWN"); + expect(sorted[5].status).toBe('UNKNOWN'); }); }); }); diff --git a/packages/bygger/src/Forms/formsListUtils.ts b/packages/bygger/src/Forms/formsListUtils.ts index fe612fe74..eb58ac8a3 100644 --- a/packages/bygger/src/Forms/formsListUtils.ts +++ b/packages/bygger/src/Forms/formsListUtils.ts @@ -1,10 +1,10 @@ -import { FormPropertiesType, NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; -import { determineStatus } from "./status/FormStatus"; -import { Status } from "./status/types"; +import { FormPropertiesType, NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; +import { determineStatus } from './status/FormStatus'; +import { Status } from './status/types'; -export type SortDirection = "ascending" | "descending"; -export type FormMetadata = Pick & - Pick & { status: Status }; +export type SortDirection = 'ascending' | 'descending'; +export type FormMetadata = Pick & + Pick & { status: Status }; export function sortFormsByProperty( formMetadataList: FormMetadata[], @@ -12,11 +12,11 @@ export function sortFormsByProperty( sortingOrder?: SortDirection, ) { return formMetadataList.sort((a, b) => { - const valueA = a[sortingKey] || ""; - const valueB = b[sortingKey] || ""; - if (sortingOrder === "ascending") { + const valueA = a[sortingKey] || ''; + const valueB = b[sortingKey] || ''; + if (sortingOrder === 'ascending') { return valueA < valueB ? -1 : 1; - } else if (sortingOrder === "descending") { + } else if (sortingOrder === 'descending') { return valueA < valueB ? 1 : -1; } return 0; @@ -28,24 +28,24 @@ export function sortByFormNumber(formMetaDataList: FormMetadata[], sortDirection return formMetaData.skjemanummer.match(/^(NAV)\s\d\d-\d\d.\d\d/); }; - if (sortDirection === "ascending") { + if (sortDirection === 'ascending') { return [ - ...sortFormsByProperty(formMetaDataList.filter(matchesNavSkjemanummer), "skjemanummer", "ascending"), + ...sortFormsByProperty(formMetaDataList.filter(matchesNavSkjemanummer), 'skjemanummer', 'ascending'), ...sortFormsByProperty( formMetaDataList.filter((data) => !matchesNavSkjemanummer(data)), - "skjemanummer", - "ascending", + 'skjemanummer', + 'ascending', ), ]; } - if (sortDirection === "descending") { + if (sortDirection === 'descending') { return [ ...sortFormsByProperty( formMetaDataList.filter((data) => !matchesNavSkjemanummer(data)), - "skjemanummer", - "descending", + 'skjemanummer', + 'descending', ), - ...sortFormsByProperty(formMetaDataList.filter(matchesNavSkjemanummer), "skjemanummer", "descending"), + ...sortFormsByProperty(formMetaDataList.filter(matchesNavSkjemanummer), 'skjemanummer', 'descending'), ]; } return formMetaDataList; @@ -62,10 +62,10 @@ export function sortByStatus(formMetadataList: FormMetadata[], sortOrder?: SortD }; const compareStatus = (thisStatus, thatStatus) => { if (thisStatus === thatStatus) return 0; - if (thisStatus === "UNKNOWN") return 1; - if (thatStatus === "UNKNOWN") return -1; - if (sortOrder === "ascending") return statusOrder[thisStatus] - statusOrder[thatStatus]; - if (sortOrder === "descending") return statusOrder[thatStatus] - statusOrder[thisStatus]; + if (thisStatus === 'UNKNOWN') return 1; + if (thatStatus === 'UNKNOWN') return -1; + if (sortOrder === 'ascending') return statusOrder[thisStatus] - statusOrder[thatStatus]; + if (sortOrder === 'descending') return statusOrder[thatStatus] - statusOrder[thisStatus]; return 0; }; return formMetadataList.sort((a, b) => compareStatus(a.status, b.status)); @@ -80,8 +80,8 @@ export function asFormMetadata(form: NavFormType): FormMetadata { title: form.title.trim(), path: form.path, tags: form.tags, - skjemanummer: form.properties ? (form.properties.skjemanummer ? form.properties.skjemanummer.trim() : "") : "", - tema: form.properties ? (form.properties.tema ? form.properties.tema : "") : "", + skjemanummer: form.properties ? (form.properties.skjemanummer ? form.properties.skjemanummer.trim() : '') : '', + tema: form.properties ? (form.properties.tema ? form.properties.tema : '') : '', status: determineStatus(form.properties), }; } diff --git a/packages/bygger/src/Forms/index.jsx b/packages/bygger/src/Forms/index.jsx index 6e2d39617..51d69e3b1 100644 --- a/packages/bygger/src/Forms/index.jsx +++ b/packages/bygger/src/Forms/index.jsx @@ -1,9 +1,9 @@ -import { Route, Routes } from "react-router-dom"; -import { useFormioForms } from "../hooks/useFormioForms"; -import { useFormioTranslations } from "../hooks/useFormioTranslations"; -import { FormPage } from "./FormPage"; -import { FormsListPage } from "./FormsListPage"; -import NewFormPage from "./NewFormPage"; +import { Route, Routes } from 'react-router-dom'; +import { useFormioForms } from '../hooks/useFormioForms'; +import { useFormioTranslations } from '../hooks/useFormioTranslations'; +import { FormPage } from './FormPage'; +import { FormsListPage } from './FormsListPage'; +import NewFormPage from './NewFormPage'; export const FormsRouter = ({ formio, serverURL }) => { const { loadForm, loadFormsList, onSave, onPublish, onUnpublish } = useFormioForms(formio); @@ -12,9 +12,9 @@ export const FormsRouter = ({ formio, serverURL }) => { return ( } /> - } /> + } /> { +describe('FormsRouter', () => { let formioFetch; beforeAll(() => { - formioFetch = vi.spyOn(NavFormioJs.Formio, "fetch"); + formioFetch = vi.spyOn(NavFormioJs.Formio, 'fetch'); formioFetch.mockImplementation(createMockImplementation()); fetchMock.mockImplementation(createMockImplementation()); }); @@ -27,7 +27,7 @@ describe("FormsRouter", () => { {}, }} > @@ -46,30 +46,30 @@ describe("FormsRouter", () => { ); } - it("lets you navigate to new form page from the list of all forms", async () => { - renderApp("/forms"); - const knapp = await screen.findByRole("button", { name: "Lag nytt skjema" }); + it('lets you navigate to new form page from the list of all forms', async () => { + renderApp('/forms'); + const knapp = await screen.findByRole('button', { name: 'Lag nytt skjema' }); await userEvent.click(knapp); - expect(await screen.findByRole("button", { name: "Opprett" })).toBeInTheDocument(); + expect(await screen.findByRole('button', { name: 'Opprett' })).toBeInTheDocument(); }); - it("can edit a form", async () => { - renderApp("/forms/debugskjema/edit"); - expect(await screen.findByRole("heading", { name: "debug skjema" })).toBeInTheDocument(); - expect(await screen.findByLabelText("Text Area", { exact: false })).toBeInTheDocument(); + it('can edit a form', async () => { + renderApp('/forms/debugskjema/edit'); + expect(await screen.findByRole('heading', { name: 'debug skjema' })).toBeInTheDocument(); + expect(await screen.findByLabelText('Text Area', { exact: false })).toBeInTheDocument(); }); - it("navigates from the list to the editor", async () => { - renderApp("/forms"); - const link = await screen.findByRole("link", { name: "debug skjema" }); + it('navigates from the list to the editor', async () => { + renderApp('/forms'); + const link = await screen.findByRole('link', { name: 'debug skjema' }); await userEvent.click(link); - expect(await screen.findByRole("heading", { name: "debug skjema" })); - expect(await screen.findByLabelText("Text Area", { exact: false })).toBeInTheDocument(); + expect(await screen.findByRole('heading', { name: 'debug skjema' })).toBeInTheDocument(); + expect(await screen.findByLabelText('Text Area', { exact: false })).toBeInTheDocument(); }); - it("displays all the forms with an edit link", async () => { - renderApp("/forms"); - const editLinks = await screen.findAllByTestId("editLink"); + it('displays all the forms with an edit link', async () => { + renderApp('/forms'); + const editLinks = await screen.findAllByTestId('editLink'); expect(editLinks).toHaveLength(2); editLinks.forEach((link) => expect(link.href).toMatch(/http:\/\/localhost(:\d+)?\/forms\/(columns|debugskjema)\/edit/), diff --git a/packages/bygger/src/Forms/publish/ConfirmPublishModal.tsx b/packages/bygger/src/Forms/publish/ConfirmPublishModal.tsx index 6cd3681ea..d11485552 100644 --- a/packages/bygger/src/Forms/publish/ConfirmPublishModal.tsx +++ b/packages/bygger/src/Forms/publish/ConfirmPublishModal.tsx @@ -1,8 +1,8 @@ -import { BodyShort, Button } from "@navikt/ds-react"; -import { Modal } from "@navikt/skjemadigitalisering-shared-components"; -import { I18nTranslations, NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; -import { useEffect, useState } from "react"; -import { useI18nState } from "../../context/i18n"; +import { BodyShort, Button } from '@navikt/ds-react'; +import { Modal } from '@navikt/skjemadigitalisering-shared-components'; +import { I18nTranslations, NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; +import { useEffect, useState } from 'react'; +import { useI18nState } from '../../context/i18n'; interface Props { form: NavFormType; diff --git a/packages/bygger/src/Forms/publish/PublishModalComponents.test.tsx b/packages/bygger/src/Forms/publish/PublishModalComponents.test.tsx index 40b9eb32f..8c218ac73 100644 --- a/packages/bygger/src/Forms/publish/PublishModalComponents.test.tsx +++ b/packages/bygger/src/Forms/publish/PublishModalComponents.test.tsx @@ -1,17 +1,17 @@ -import { Modal } from "@navikt/skjemadigitalisering-shared-components"; -import { MockedComponentObjectForTest } from "@navikt/skjemadigitalisering-shared-domain"; -import { render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import PublishModalComponents from "./PublishModalComponents"; +import { Modal } from '@navikt/skjemadigitalisering-shared-components'; +import { MockedComponentObjectForTest } from '@navikt/skjemadigitalisering-shared-domain'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import PublishModalComponents from './PublishModalComponents'; const { createDummyAttachment, createFormObject, createPanelObject } = MockedComponentObjectForTest; -Modal.setAppElement(document.createElement("div")); +Modal.setAppElement(document.createElement('div')); const ERROR_MESSAGE_MISSING_KODE_OR_TITTEL = - "Du må fylle ut vedleggskode og vedleggstittel for alle vedlegg før skjemaet kan publiseres."; + 'Du må fylle ut vedleggskode og vedleggstittel for alle vedlegg før skjemaet kan publiseres.'; -describe("PublishModalComponents", () => { +describe('PublishModalComponents', () => { let mockedCloseModal; let mockedOnPublish; const renderPublishSettingsModal = (form) => { @@ -29,99 +29,99 @@ describe("PublishModalComponents", () => { const createFormWithAttachment = (attachmentProps) => createFormObject( - [createPanelObject("Personinformasjon", [createDummyAttachment("Bekreftelse fra skole", attachmentProps)])], - "Veiledning", + [createPanelObject('Personinformasjon', [createDummyAttachment('Bekreftelse fra skole', attachmentProps)])], + 'Veiledning', ); - describe("When attachment definition is complete", () => { + describe('When attachment definition is complete', () => { beforeEach(() => { const form = createFormWithAttachment({ - vedleggstittel: "Bekreftelse fra skole", - vedleggskode: "B1", - vedleggErValgfritt: "ja", + vedleggstittel: 'Bekreftelse fra skole', + vedleggskode: 'B1', + vedleggErValgfritt: 'ja', }); renderPublishSettingsModal(form); }); - it("the publish button is visible", () => { - const publishButton = screen.queryByRole("button", { name: "Publiser" }); + it('the publish button is visible', () => { + const publishButton = screen.queryByRole('button', { name: 'Publiser' }); expect(publishButton).toBeInTheDocument(); }); it("confirm modal is shown when clicking 'Publiser' button", async () => { - const publishButton = screen.queryByRole("button", { name: "Publiser" }); + const publishButton = screen.queryByRole('button', { name: 'Publiser' }); expect(publishButton).toBeInTheDocument(); await userEvent.click(publishButton!); - expect(screen.queryByText("Er du sikker på at dette skjemaet skal publiseres?")).toBeInTheDocument(); - expect(screen.queryByRole("button", { name: "Ja, publiser skjemaet" })).toBeInTheDocument(); - expect(screen.queryByRole("button", { name: "Nei, ikke publiser skjemaet" })).toBeInTheDocument(); + expect(screen.queryByText('Er du sikker på at dette skjemaet skal publiseres?')).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Ja, publiser skjemaet' })).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Nei, ikke publiser skjemaet' })).toBeInTheDocument(); }); - it("no error message is rendered", () => { + it('no error message is rendered', () => { const feilmelding = screen.queryByText(ERROR_MESSAGE_MISSING_KODE_OR_TITTEL); expect(feilmelding).not.toBeInTheDocument(); }); }); - describe("When vedleggskode is missing in attachment definition", () => { + describe('When vedleggskode is missing in attachment definition', () => { beforeEach(() => { const form = createFormWithAttachment({ - vedleggstittel: "Bekreftelse fra skole", - vedleggskode: "", - vedleggErValgfritt: "ja", + vedleggstittel: 'Bekreftelse fra skole', + vedleggskode: '', + vedleggErValgfritt: 'ja', }); renderPublishSettingsModal(form); }); - it("the publish button is not visible", () => { - const publishButton = screen.queryByRole("button", { name: "Publiser" }); + it('the publish button is not visible', () => { + const publishButton = screen.queryByRole('button', { name: 'Publiser' }); expect(publishButton).not.toBeInTheDocument(); }); - it("an error message is rendered", () => { + it('an error message is rendered', () => { const feilmelding = screen.queryByText(ERROR_MESSAGE_MISSING_KODE_OR_TITTEL); expect(feilmelding).toBeInTheDocument(); }); }); - describe("When vedleggstittel is missing in attachment definition", () => { + describe('When vedleggstittel is missing in attachment definition', () => { beforeEach(() => { const form = createFormWithAttachment({ - vedleggstittel: "", - vedleggskode: "B1", - vedleggErValgfritt: "ja", + vedleggstittel: '', + vedleggskode: 'B1', + vedleggErValgfritt: 'ja', }); renderPublishSettingsModal(form); }); - it("the publish button is not visible", () => { - const publishButton = screen.queryByRole("button", { name: "Publiser" }); + it('the publish button is not visible', () => { + const publishButton = screen.queryByRole('button', { name: 'Publiser' }); expect(publishButton).not.toBeInTheDocument(); }); - it("an error message is rendered", () => { + it('an error message is rendered', () => { const feilmelding = screen.queryByText(ERROR_MESSAGE_MISSING_KODE_OR_TITTEL); expect(feilmelding).toBeInTheDocument(); }); }); - describe("When both vedleggskode and vedleggstittel is missing in attachment definition", () => { + describe('When both vedleggskode and vedleggstittel is missing in attachment definition', () => { beforeEach(() => { const form = createFormWithAttachment({ - vedleggstittel: "", - vedleggskode: "", - vedleggErValgfritt: "ja", + vedleggstittel: '', + vedleggskode: '', + vedleggErValgfritt: 'ja', }); renderPublishSettingsModal(form); }); - it("the publish button is not visible", () => { - const publishButton = screen.queryByRole("button", { name: "Publiser" }); + it('the publish button is not visible', () => { + const publishButton = screen.queryByRole('button', { name: 'Publiser' }); expect(publishButton).not.toBeInTheDocument(); }); - it("an error message is rendered", () => { + it('an error message is rendered', () => { const feilmelding = screen.queryByText(ERROR_MESSAGE_MISSING_KODE_OR_TITTEL); expect(feilmelding).toBeInTheDocument(); }); diff --git a/packages/bygger/src/Forms/publish/PublishModalComponents.tsx b/packages/bygger/src/Forms/publish/PublishModalComponents.tsx index 28ee41314..27bd6479e 100644 --- a/packages/bygger/src/Forms/publish/PublishModalComponents.tsx +++ b/packages/bygger/src/Forms/publish/PublishModalComponents.tsx @@ -1,11 +1,11 @@ -import { Component, navFormUtils } from "@navikt/skjemadigitalisering-shared-domain"; -import { useEffect, useState } from "react"; -import UserMessageModal, { useUserMessage } from "../../components/UserMessageModal"; -import { useModal } from "../../util/useModal"; -import ConfirmPublishModal from "./ConfirmPublishModal"; -import PublishSettingsModal from "./PublishSettingsModal"; +import { Component, navFormUtils } from '@navikt/skjemadigitalisering-shared-domain'; +import { useEffect, useState } from 'react'; +import UserMessageModal, { useUserMessage } from '../../components/UserMessageModal'; +import { useModal } from '../../util/useModal'; +import ConfirmPublishModal from './ConfirmPublishModal'; +import PublishSettingsModal from './PublishSettingsModal'; -const isAttachment = (comp: Component) => comp.values?.some((v) => v.value === "leggerVedNaa"); +const isAttachment = (comp: Component) => comp.values?.some((v) => v.value === 'leggerVedNaa'); const validateAttachments = (form) => navFormUtils @@ -26,7 +26,7 @@ const PublishModalComponents = ({ form, onPublish, openPublishSettingModal, setO setOpenPublishSettingModalValidated(true); } else { setOpenPublishSettingModal(false); - showUserMessage("Du må fylle ut vedleggskode og vedleggstittel for alle vedlegg før skjemaet kan publiseres."); + showUserMessage('Du må fylle ut vedleggskode og vedleggstittel for alle vedlegg før skjemaet kan publiseres.'); } } else { setOpenPublishSettingModalValidated(false); diff --git a/packages/bygger/src/Forms/publish/PublishSettingsModal.test.tsx b/packages/bygger/src/Forms/publish/PublishSettingsModal.test.tsx index df241000a..e13e40fc5 100644 --- a/packages/bygger/src/Forms/publish/PublishSettingsModal.test.tsx +++ b/packages/bygger/src/Forms/publish/PublishSettingsModal.test.tsx @@ -1,31 +1,31 @@ -import { Modal } from "@navikt/skjemadigitalisering-shared-components"; -import { MockedComponentObjectForTest } from "@navikt/skjemadigitalisering-shared-domain"; -import { render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import PublishSettingsModal, { getCompleteTranslationLanguageCodeList } from "./PublishSettingsModal"; +import { Modal } from '@navikt/skjemadigitalisering-shared-components'; +import { MockedComponentObjectForTest } from '@navikt/skjemadigitalisering-shared-domain'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import PublishSettingsModal, { getCompleteTranslationLanguageCodeList } from './PublishSettingsModal'; const { createDummyRadioPanel, createFormObject, createPanelObject, createFormPropertiesObject } = MockedComponentObjectForTest; -vi.mock("../../context/i18n/index", () => { +vi.mock('../../context/i18n/index', () => { const languagesInNorwegian = { - "nn-NO": "Norsk nynorsk", - en: "Engelsk", - pl: "Polsk", + 'nn-NO': 'Norsk nynorsk', + en: 'Engelsk', + pl: 'Polsk', }; const mockTranslationsForNavForm = { en: { - "Bor du i Norge?": "Do you live in Norway?", - Veiledning: "Guidance", - "NO-label": "no", - "YES-label": "yes", - "Dine opplysninger": "Your information", - Personinformasjon: "Personal information", - "Hei verden": "Hello world", - "Hei panel": "Hello panel", + 'Bor du i Norge?': 'Do you live in Norway?', + Veiledning: 'Guidance', + 'NO-label': 'no', + 'YES-label': 'yes', + 'Dine opplysninger': 'Your information', + Personinformasjon: 'Personal information', + 'Hei verden': 'Hello world', + 'Hei panel': 'Hello panel', }, - "nn-NO": { "YES-label": "yes", "Hei verden": "Hei verda", "Hei panel": "Hei panel" }, + 'nn-NO': { 'YES-label': 'yes', 'Hei verden': 'Hei verda', 'Hei panel': 'Hei panel' }, }; const mockUseI18nState = () => ({ translationsForNavForm: mockTranslationsForNavForm, @@ -36,9 +36,9 @@ vi.mock("../../context/i18n/index", () => { }; }); -Modal.setAppElement(document.createElement("div")); +Modal.setAppElement(document.createElement('div')); -describe("PublishSettingsModal", () => { +describe('PublishSettingsModal', () => { let mockedCloseModal; let mockedOnPublish; const renderPublishSettingsModal = (form) => { @@ -49,146 +49,146 @@ describe("PublishSettingsModal", () => { ); }; - it("renders disabled checkbox for Norsk bokmål", () => { - const form = createFormObject([createPanelObject("test", [createDummyRadioPanel("Bor du i Sverige?")])]); + it('renders disabled checkbox for Norsk bokmål', () => { + const form = createFormObject([createPanelObject('test', [createDummyRadioPanel('Bor du i Sverige?')])]); renderPublishSettingsModal(form); - expect(screen.queryByRole("checkbox", { name: "Norsk bokmål (NB-NO)" })).toBeInTheDocument(); - expect(screen.queryByRole("checkbox", { name: "Norsk bokmål (NB-NO)" })).toBeChecked(); - expect(screen.queryByRole("checkbox", { name: "Norsk bokmål (NB-NO)" })).toBeDisabled(); + expect(screen.queryByRole('checkbox', { name: 'Norsk bokmål (NB-NO)' })).toBeInTheDocument(); + expect(screen.queryByRole('checkbox', { name: 'Norsk bokmål (NB-NO)' })).toBeChecked(); + expect(screen.queryByRole('checkbox', { name: 'Norsk bokmål (NB-NO)' })).toBeDisabled(); }); - it("renders checked checkbox for language with complete translation", async () => { + it('renders checked checkbox for language with complete translation', async () => { const form = createFormObject( - [createPanelObject("Dine opplysninger", [createDummyRadioPanel("Bor du i Norge?")])], - "Veiledning", + [createPanelObject('Dine opplysninger', [createDummyRadioPanel('Bor du i Norge?')])], + 'Veiledning', ); renderPublishSettingsModal(form); - expect(screen.queryByRole("checkbox", { name: "Engelsk (EN)" })).toBeInTheDocument(); - expect(screen.queryByRole("checkbox", { name: "Engelsk (EN)" })).toBeChecked(); - expect(screen.queryByRole("checkbox", { name: "Norsk nynorsk (NN-NO)" })).not.toBeInTheDocument(); + expect(screen.queryByRole('checkbox', { name: 'Engelsk (EN)' })).toBeInTheDocument(); + expect(screen.queryByRole('checkbox', { name: 'Engelsk (EN)' })).toBeChecked(); + expect(screen.queryByRole('checkbox', { name: 'Norsk nynorsk (NN-NO)' })).not.toBeInTheDocument(); }); - it("renders disabled checkbox for previously published language when current translation is incomplete", async () => { + it('renders disabled checkbox for previously published language when current translation is incomplete', async () => { const form = createFormObject( - [createPanelObject("Dine opplysninger", [createDummyRadioPanel("Bor du i Norge?")])], - "Veiledning", - createFormPropertiesObject({ publishedLanguages: ["nn-NO"] }), + [createPanelObject('Dine opplysninger', [createDummyRadioPanel('Bor du i Norge?')])], + 'Veiledning', + createFormPropertiesObject({ publishedLanguages: ['nn-NO'] }), ); renderPublishSettingsModal(form); - expect(screen.queryByRole("checkbox", { name: "Norsk nynorsk (NN-NO)" })).toBeInTheDocument(); - expect(screen.queryByRole("checkbox", { name: "Norsk nynorsk (NN-NO)" })).toBeDisabled(); - expect(screen.queryByRole("checkbox", { name: "Norsk nynorsk (NN-NO)" })).not.toBeChecked(); + expect(screen.queryByRole('checkbox', { name: 'Norsk nynorsk (NN-NO)' })).toBeInTheDocument(); + expect(screen.queryByRole('checkbox', { name: 'Norsk nynorsk (NN-NO)' })).toBeDisabled(); + expect(screen.queryByRole('checkbox', { name: 'Norsk nynorsk (NN-NO)' })).not.toBeChecked(); }); - it("displays a warning when checkbox for previously published translation is unchecked", async () => { + it('displays a warning when checkbox for previously published translation is unchecked', async () => { const form = createFormObject( - [createPanelObject("Dine opplysninger", [createDummyRadioPanel("Bor du i Norge?")])], - "Veiledning", - createFormPropertiesObject({ publishedLanguages: ["en"] }), + [createPanelObject('Dine opplysninger', [createDummyRadioPanel('Bor du i Norge?')])], + 'Veiledning', + createFormPropertiesObject({ publishedLanguages: ['en'] }), ); renderPublishSettingsModal(form); expect( - screen.queryByText("OBS! Engelsk (EN) vil bli avpublisert hvis du publiserer med disse innstillingene."), + screen.queryByText('OBS! Engelsk (EN) vil bli avpublisert hvis du publiserer med disse innstillingene.'), ).not.toBeInTheDocument(); - await userEvent.click(await screen.findByRole("checkbox", { name: "Engelsk (EN)" })); + await userEvent.click(await screen.findByRole('checkbox', { name: 'Engelsk (EN)' })); expect( - screen.queryByText("OBS! Engelsk (EN) vil bli avpublisert hvis du publiserer med disse innstillingene."), + screen.queryByText('OBS! Engelsk (EN) vil bli avpublisert hvis du publiserer med disse innstillingene.'), ).toBeInTheDocument(); }); - it("displays a warning when previously published translation currently is incomplete", () => { + it('displays a warning when previously published translation currently is incomplete', () => { const form = createFormObject( - [createPanelObject("Dine opplysninger", [createDummyRadioPanel("Bor du i Norge?")])], - "Veiledning", - createFormPropertiesObject({ publishedLanguages: ["nn-NO"] }), + [createPanelObject('Dine opplysninger', [createDummyRadioPanel('Bor du i Norge?')])], + 'Veiledning', + createFormPropertiesObject({ publishedLanguages: ['nn-NO'] }), ); renderPublishSettingsModal(form); expect( - screen.queryByText("OBS! Norsk nynorsk (NN-NO) vil bli avpublisert hvis du publiserer med disse innstillingene."), + screen.queryByText('OBS! Norsk nynorsk (NN-NO) vil bli avpublisert hvis du publiserer med disse innstillingene.'), ).toBeInTheDocument(); }); - it("publish will send en-languageCode if the English checkbox is checked ", async () => { + it('publish will send en-languageCode if the English checkbox is checked', async () => { const form = createFormObject( - [createPanelObject("Personinformasjon", [createDummyRadioPanel("Bor du i Norge?")])], - "Veiledning", + [createPanelObject('Personinformasjon', [createDummyRadioPanel('Bor du i Norge?')])], + 'Veiledning', ); renderPublishSettingsModal(form); - const englishCheckbox = await screen.findByRole("checkbox", { name: "Engelsk (EN)" }); + const englishCheckbox = await screen.findByRole('checkbox', { name: 'Engelsk (EN)' }); expect(englishCheckbox).toBeTruthy(); - expect(screen.queryByRole("checkbox", { name: "Norsk nynorsk (NN-NO)" })).not.toBeInTheDocument(); - await userEvent.click(screen.getByRole("button", { name: "Publiser" })); + expect(screen.queryByRole('checkbox', { name: 'Norsk nynorsk (NN-NO)' })).not.toBeInTheDocument(); + await userEvent.click(screen.getByRole('button', { name: 'Publiser' })); expect(mockedOnPublish).toBeCalled(); - expect(mockedOnPublish.mock.calls[0][0]).toEqual(["en"]); + expect(mockedOnPublish.mock.calls[0][0]).toEqual(['en']); }); - it("publishes all checked languages", async () => { - const form = createFormObject([createPanelObject("Hei panel")], "Hei verden"); + it('publishes all checked languages', async () => { + const form = createFormObject([createPanelObject('Hei panel')], 'Hei verden'); renderPublishSettingsModal(form); - expect(screen.queryByRole("checkbox", { name: "Norsk nynorsk (NN-NO)" })).toBeInTheDocument(); - expect(screen.queryByRole("checkbox", { name: "Norsk nynorsk (NN-NO)" })).toBeChecked(); - expect(screen.queryByRole("checkbox", { name: "Engelsk (EN)" })).toBeInTheDocument(); - expect(screen.queryByRole("checkbox", { name: "Engelsk (EN)" })).toBeChecked(); - await userEvent.click(screen.getByRole("button", { name: "Publiser" })); + expect(screen.queryByRole('checkbox', { name: 'Norsk nynorsk (NN-NO)' })).toBeInTheDocument(); + expect(screen.queryByRole('checkbox', { name: 'Norsk nynorsk (NN-NO)' })).toBeChecked(); + expect(screen.queryByRole('checkbox', { name: 'Engelsk (EN)' })).toBeInTheDocument(); + expect(screen.queryByRole('checkbox', { name: 'Engelsk (EN)' })).toBeChecked(); + await userEvent.click(screen.getByRole('button', { name: 'Publiser' })); expect(mockedOnPublish).toBeCalled(); - expect(mockedOnPublish.mock.calls[0][0]).toEqual(["en", "nn-NO"]); + expect(mockedOnPublish.mock.calls[0][0]).toEqual(['en', 'nn-NO']); }); - it("onPublish will send empty array when the English checkbox is checked off", async () => { + it('onPublish will send empty array when the English checkbox is checked off', async () => { const form = createFormObject( - [createPanelObject("Personinformasjon", [createDummyRadioPanel("Bor du i Norge?")])], - "Veiledning", + [createPanelObject('Personinformasjon', [createDummyRadioPanel('Bor du i Norge?')])], + 'Veiledning', ); renderPublishSettingsModal(form); - const englishCheckbox = await screen.findByRole("checkbox", { name: "Engelsk (EN)" }); + const englishCheckbox = await screen.findByRole('checkbox', { name: 'Engelsk (EN)' }); expect(englishCheckbox).toBeTruthy(); - expect(screen.queryByRole("checkbox", { name: "Norsk nynorsk (NN-NO)" })).not.toBeInTheDocument(); - await userEvent.click(await screen.findByRole("checkbox", { name: "Engelsk (EN)" })); - await userEvent.click(screen.getByRole("button", { name: "Publiser" })); + expect(screen.queryByRole('checkbox', { name: 'Norsk nynorsk (NN-NO)' })).not.toBeInTheDocument(); + await userEvent.click(await screen.findByRole('checkbox', { name: 'Engelsk (EN)' })); + await userEvent.click(screen.getByRole('button', { name: 'Publiser' })); expect(mockedOnPublish).toBeCalled(); expect(mockedOnPublish.mock.calls[0][0]).toEqual([]); }); }); -describe("getCompleteTranslationLanguageCodeList", () => { - it("return empty list when there is no form text and translation", () => { +describe('getCompleteTranslationLanguageCodeList', () => { + it('return empty list when there is no form text and translation', () => { const actual = getCompleteTranslationLanguageCodeList([], {}); expect(actual).toEqual([]); }); - it("return empty list when there are form text and but no translation", () => { - const actual = getCompleteTranslationLanguageCodeList(["Bor du i Norge", "Ja", "Nei"], {}); + it('return empty list when there are form text and but no translation', () => { + const actual = getCompleteTranslationLanguageCodeList(['Bor du i Norge', 'Ja', 'Nei'], {}); expect(actual).toEqual([]); }); - it("return empty list when there are form text and not complete translations", () => { - const actual = getCompleteTranslationLanguageCodeList(["Bor du i Norge?", "Ja", "Nei"], { - en: { "Bor du i Norge?": "Do you live in Norway?" }, - "nn-NO": { Ja: "Yes" }, + it('return empty list when there are form text and not complete translations', () => { + const actual = getCompleteTranslationLanguageCodeList(['Bor du i Norge?', 'Ja', 'Nei'], { + en: { 'Bor du i Norge?': 'Do you live in Norway?' }, + 'nn-NO': { Ja: 'Yes' }, }); expect(actual).toEqual([]); }); - it("return en when there are form text and complete English translations", () => { - const actual = getCompleteTranslationLanguageCodeList(["Bor du i Norge?", "Ja", "Nei"], { - en: { "Bor du i Norge?": "Do you live in Norway?", Ja: "Yes", Nei: "No" }, - "nn-NO": { Ja: "Ja" }, + it('return en when there are form text and complete English translations', () => { + const actual = getCompleteTranslationLanguageCodeList(['Bor du i Norge?', 'Ja', 'Nei'], { + en: { 'Bor du i Norge?': 'Do you live in Norway?', Ja: 'Yes', Nei: 'No' }, + 'nn-NO': { Ja: 'Ja' }, }); - expect(actual).toEqual(["en"]); + expect(actual).toEqual(['en']); }); - it("return en and nn-NO when there are form text and complete English and Nynorsk translations", () => { - const actual = getCompleteTranslationLanguageCodeList(["Bor du i Norge?", "Ja", "Nei"], { - en: { "Bor du i Norge?": "Do you live in Norway?", Ja: "Yes", Nei: "No" }, - "nn-NO": { "Bor du i Norge?": "Bor du i Norge?", Ja: "Ja", Nei: "Nei", Takk: "Takk" }, + it('return en and nn-NO when there are form text and complete English and Nynorsk translations', () => { + const actual = getCompleteTranslationLanguageCodeList(['Bor du i Norge?', 'Ja', 'Nei'], { + en: { 'Bor du i Norge?': 'Do you live in Norway?', Ja: 'Yes', Nei: 'No' }, + 'nn-NO': { 'Bor du i Norge?': 'Bor du i Norge?', Ja: 'Ja', Nei: 'Nei', Takk: 'Takk' }, }); - expect(actual).toEqual(["en", "nn-NO"]); + expect(actual).toEqual(['en', 'nn-NO']); }); - it("does not include nb-NO even if complete", () => { - const actual = getCompleteTranslationLanguageCodeList(["Bor du i Norge?", "Ja", "Nei"], { - en: { "Bor du i Norge?": "Do you live in Norway?", Ja: "Yes", Nei: "No" }, - "nn-NO": { "Bor du i Norge?": "Bur du i Noreg?", Ja: "Ja", Nei: "Nei", Takk: "Takk" }, - "nb-NO": { "Bor du i Norge?": "Bor du i Norge?", Ja: "Ja", Nei: "Nei", Takk: "Takk" }, + it('does not include nb-NO even if complete', () => { + const actual = getCompleteTranslationLanguageCodeList(['Bor du i Norge?', 'Ja', 'Nei'], { + en: { 'Bor du i Norge?': 'Do you live in Norway?', Ja: 'Yes', Nei: 'No' }, + 'nn-NO': { 'Bor du i Norge?': 'Bur du i Noreg?', Ja: 'Ja', Nei: 'Nei', Takk: 'Takk' }, + 'nb-NO': { 'Bor du i Norge?': 'Bor du i Norge?', Ja: 'Ja', Nei: 'Nei', Takk: 'Takk' }, }); - expect(actual).toEqual(["en", "nn-NO"]); + expect(actual).toEqual(['en', 'nn-NO']); }); }); diff --git a/packages/bygger/src/Forms/publish/PublishSettingsModal.tsx b/packages/bygger/src/Forms/publish/PublishSettingsModal.tsx index 1c352cddd..38d8d793f 100644 --- a/packages/bygger/src/Forms/publish/PublishSettingsModal.tsx +++ b/packages/bygger/src/Forms/publish/PublishSettingsModal.tsx @@ -1,18 +1,18 @@ -import { Alert, Button, Checkbox, CheckboxGroup, Heading, Panel } from "@navikt/ds-react"; -import { Modal, makeStyles } from "@navikt/skjemadigitalisering-shared-components"; -import { FormPropertiesType, I18nTranslations, NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; -import { useEffect, useState } from "react"; -import { languagesInNorwegian, useI18nState } from "../../context/i18n"; -import { getFormTexts } from "../../translations/utils"; -import FormStatus, { determineStatus } from "../status/FormStatus"; -import { allLanguagesInNorwegian } from "../status/PublishedLanguages"; -import Timestamp from "../status/Timestamp"; -import { useStatusStyles } from "../status/styles"; +import { Alert, Button, Checkbox, CheckboxGroup, Heading, Panel } from '@navikt/ds-react'; +import { Modal, makeStyles } from '@navikt/skjemadigitalisering-shared-components'; +import { FormPropertiesType, I18nTranslations, NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; +import { useEffect, useState } from 'react'; +import { languagesInNorwegian, useI18nState } from '../../context/i18n'; +import { getFormTexts } from '../../translations/utils'; +import FormStatus, { determineStatus } from '../status/FormStatus'; +import { allLanguagesInNorwegian } from '../status/PublishedLanguages'; +import Timestamp from '../status/Timestamp'; +import { useStatusStyles } from '../status/styles'; const useModalStyles = makeStyles({ modal_button: { - float: "right", - margin: "1rem", + float: 'right', + margin: '1rem', }, languageList: { margin: 0, @@ -21,13 +21,13 @@ const useModalStyles = makeStyles({ const useStatusPanelStyles = makeStyles({ panel: { - display: "flex", - padding: "0 0.5rem", - margin: "2rem 0", - backgroundColor: "var(--navds-semantic-color-canvas-background)", + display: 'flex', + padding: '0 0.5rem', + margin: '2rem 0', + backgroundColor: 'var(--navds-semantic-color-canvas-background)', }, table: { - width: "100%", + width: '100%', }, }); @@ -45,7 +45,7 @@ export const getCompleteTranslationLanguageCodeList = ( const completeTranslationList: string[] = []; if (allFormOriginalTexts.length !== 0) { Object.keys(translationsForNavForm) - .filter((lang) => lang !== "nb-NO") + .filter((lang) => lang !== 'nb-NO') .forEach((languageCode) => { const incompleteTranslationList: string[] = allFormOriginalTexts.filter( (formText) => Object.keys(translationsForNavForm[languageCode]).indexOf(formText) < 0, @@ -78,7 +78,7 @@ const PublishSettingsModal = ({ openModal, closeModal, onPublish, form }: Props) useEffect(() => { const completeTranslations = getCompleteTranslationLanguageCodeList(allFormOriginalTexts, translationsForNavForm); setCompleteTranslationLanguageCodeList(completeTranslations); - setCheckedLanguages([...completeTranslations, "nb-NO"]); + setCheckedLanguages([...completeTranslations, 'nb-NO']); }, [allFormOriginalTexts, translationsForNavForm]); const PublishStatusPanel = ({ formProperties }: { formProperties: FormPropertiesType }) => { @@ -103,7 +103,7 @@ const PublishSettingsModal = ({ openModal, closeModal, onPublish, form }: Props) {formProperties.published && (
      -
    • {allLanguagesInNorwegian["nb-NO"]}
    • +
    • {allLanguagesInNorwegian['nb-NO']}
    • {formProperties.publishedLanguages?.map((languageCode) => (
    • {languagesInNorwegian[languageCode]}
    • ))} @@ -151,7 +151,7 @@ const PublishSettingsModal = ({ openModal, closeModal, onPublish, form }: Props) setCheckedLanguages(checked); }} > - {`${allLanguagesInNorwegian["nb-NO"]} (NB-NO)`} + {`${allLanguagesInNorwegian['nb-NO']} (NB-NO)`} {checkedLanguages.length > 0 && Object.keys(languagesInNorwegian).map((languageCode) => { if (isTranslationComplete(languageCode)) { diff --git a/packages/bygger/src/Forms/status/FormStatus.tsx b/packages/bygger/src/Forms/status/FormStatus.tsx index aaabb58ec..2d0f3adb7 100644 --- a/packages/bygger/src/Forms/status/FormStatus.tsx +++ b/packages/bygger/src/Forms/status/FormStatus.tsx @@ -1,7 +1,7 @@ -import moment from "moment"; -import FormStatusIndicator from "./FormStatusIndicator"; -import { useStatusStyles } from "./styles"; -import { PublishStatusProperties, Status, StreetLightSize } from "./types"; +import moment from 'moment'; +import FormStatusIndicator from './FormStatusIndicator'; +import { useStatusStyles } from './styles'; +import { PublishStatusProperties, Status, StreetLightSize } from './types'; export function determineStatus(publishProperties: PublishStatusProperties): Status { const { modified, published, isTestForm, unpublished } = publishProperties; @@ -9,23 +9,23 @@ export function determineStatus(publishProperties: PublishStatusProperties): Sta const unpublishedDate = unpublished !== undefined ? moment(unpublished) : undefined; if (isTestForm) { - return "TESTFORM"; + return 'TESTFORM'; } if (modified && published) { if (moment(modified).isAfter(moment(published))) { - return "PENDING"; + return 'PENDING'; } - return "PUBLISHED"; + return 'PUBLISHED'; } if (unpublishedDate?.isSameOrAfter(modifiedDate)) { - return "UNPUBLISHED"; + return 'UNPUBLISHED'; } else if (modified) { - return "DRAFT"; + return 'DRAFT'; } - return "UNKNOWN"; + return 'UNKNOWN'; } type FormStatusProps = { status: Status; size: StreetLightSize }; @@ -33,12 +33,12 @@ type FormStatusProps = { status: Status; size: StreetLightSize }; const FormStatus = ({ status, size }: FormStatusProps) => { const styles = useStatusStyles({}); const statusTexts: Record = { - PUBLISHED: "Publisert", - UNPUBLISHED: "Avpublisert", - PENDING: "Upubliserte endringer", - DRAFT: "Utkast", - UNKNOWN: "Ukjent status", - TESTFORM: "Testskjema", + PUBLISHED: 'Publisert', + UNPUBLISHED: 'Avpublisert', + PENDING: 'Upubliserte endringer', + DRAFT: 'Utkast', + UNKNOWN: 'Ukjent status', + TESTFORM: 'Testskjema', }; return (
      diff --git a/packages/bygger/src/Forms/status/FormStatusIndicator.tsx b/packages/bygger/src/Forms/status/FormStatusIndicator.tsx index da62b893b..e2d3d3c7d 100644 --- a/packages/bygger/src/Forms/status/FormStatusIndicator.tsx +++ b/packages/bygger/src/Forms/status/FormStatusIndicator.tsx @@ -1,21 +1,21 @@ -import { useFormStatusIndicatorStyles } from "./styles"; -import { Status, StreetLightSize } from "./types"; +import { useFormStatusIndicatorStyles } from './styles'; +import { Status, StreetLightSize } from './types'; const FormStatusIndicator = ({ status, size }: { status: Status; size: StreetLightSize }) => { // @ts-ignore const styles = useFormStatusIndicatorStyles({ size }); switch (status) { - case "PUBLISHED": + case 'PUBLISHED': return ; - case "PENDING": + case 'PENDING': return ; - case "DRAFT": + case 'DRAFT': return ; - case "UNPUBLISHED": + case 'UNPUBLISHED': return ; - case "TESTFORM": + case 'TESTFORM': return ; - case "UNKNOWN": + case 'UNKNOWN': default: return <>; } diff --git a/packages/bygger/src/Forms/status/FormStatusPanel.test.tsx b/packages/bygger/src/Forms/status/FormStatusPanel.test.tsx index dc6b1f47d..83d8e6c85 100644 --- a/packages/bygger/src/Forms/status/FormStatusPanel.test.tsx +++ b/packages/bygger/src/Forms/status/FormStatusPanel.test.tsx @@ -1,68 +1,68 @@ -import { AppConfigProvider } from "@navikt/skjemadigitalisering-shared-components"; -import { FormPropertiesType } from "@navikt/skjemadigitalisering-shared-domain"; -import { render, screen } from "@testing-library/react"; -import moment from "moment"; -import FormStatusPanel from "./FormStatusPanel"; -import { allLanguagesInNorwegian } from "./PublishedLanguages"; +import { AppConfigProvider } from '@navikt/skjemadigitalisering-shared-components'; +import { FormPropertiesType } from '@navikt/skjemadigitalisering-shared-domain'; +import { render, screen } from '@testing-library/react'; +import moment from 'moment'; +import FormStatusPanel from './FormStatusPanel'; +import { allLanguagesInNorwegian } from './PublishedLanguages'; type PartialFormProperties = Pick< FormPropertiesType, - "modified" | "modifiedBy" | "published" | "publishedBy" | "isTestForm" | "unpublished" + 'modified' | 'modifiedBy' | 'published' | 'publishedBy' | 'isTestForm' | 'unpublished' >; -describe("FormStatusPanel", () => { +describe('FormStatusPanel', () => { const now = moment().toISOString(); - const earlier = moment(now).subtract("1", "day").toISOString(); + const earlier = moment(now).subtract('1', 'day').toISOString(); - describe("When form has modified date and no publish date", () => { - const properties: PartialFormProperties = { modified: now, modifiedBy: "Jenny" }; + describe('When form has modified date and no publish date', () => { + const properties: PartialFormProperties = { modified: now, modifiedBy: 'Jenny' }; beforeEach(() => { render(); }); it("displays the 'Utkast' status", () => { - expect(screen.getByText("Utkast")).toBeInTheDocument(); + expect(screen.getByText('Utkast')).toBeInTheDocument(); }); it("displays 'Lagret dato'", () => { - expect(screen.getByText("Sist lagret:")).toBeInTheDocument(); + expect(screen.getByText('Sist lagret:')).toBeInTheDocument(); }); - it("displays name of modifier", () => { - expect(screen.getByText("Jenny")).toBeInTheDocument(); + it('displays name of modifier', () => { + expect(screen.getByText('Jenny')).toBeInTheDocument(); }); it("does not display 'Sist publisert'", () => { - expect(screen.queryByText("Sist publisert:")).toBeNull(); + expect(screen.queryByText('Sist publisert:')).toBeNull(); }); }); - describe("When form has published date that is the same as modified date", () => { - const properties: PartialFormProperties = { modified: now, published: now, publishedBy: "Jonny" }; + describe('When form has published date that is the same as modified date', () => { + const properties: PartialFormProperties = { modified: now, published: now, publishedBy: 'Jonny' }; beforeEach(() => { render(); }); it("displays the 'Publisert' status", () => { - expect(screen.getByText("Publisert")).toBeInTheDocument(); + expect(screen.getByText('Publisert')).toBeInTheDocument(); }); it("displays 'Sist lagret'", () => { - expect(screen.getByText("Sist lagret:")).toBeInTheDocument(); + expect(screen.getByText('Sist lagret:')).toBeInTheDocument(); }); it("displays 'Sist publisert'", () => { - expect(screen.getByText("Sist publisert:")).toBeInTheDocument(); + expect(screen.getByText('Sist publisert:')).toBeInTheDocument(); }); - it("displays name of publisher", () => { - expect(screen.getByText("Jonny")).toBeInTheDocument(); + it('displays name of publisher', () => { + expect(screen.getByText('Jonny')).toBeInTheDocument(); }); }); - describe("When form has published date earlier than modified date", () => { + describe('When form has published date earlier than modified date', () => { const properties: PartialFormProperties = { modified: now, published: earlier }; beforeEach(() => { @@ -70,94 +70,94 @@ describe("FormStatusPanel", () => { }); it("displays the 'Upubliserte endringer' status", () => { - expect(screen.getByText("Upubliserte endringer")).toBeInTheDocument(); + expect(screen.getByText('Upubliserte endringer')).toBeInTheDocument(); }); it("displays 'Sist lagret'", () => { - expect(screen.getByText("Sist lagret:")).toBeInTheDocument(); + expect(screen.getByText('Sist lagret:')).toBeInTheDocument(); }); it("displays 'Sist publisert'", () => { - expect(screen.getByText("Sist publisert:")).toBeInTheDocument(); + expect(screen.getByText('Sist publisert:')).toBeInTheDocument(); }); }); - describe("When form has no modified date and no published date", () => { + describe('When form has no modified date and no published date', () => { beforeEach(() => { render(); }); it("displays the 'Ukjent status' status", () => { - expect(screen.getByText("Ukjent status")).toBeInTheDocument(); + expect(screen.getByText('Ukjent status')).toBeInTheDocument(); }); it("displays 'Sist lagret'", () => { - expect(screen.queryByText("Sist lagret:")).toBeNull(); + expect(screen.queryByText('Sist lagret:')).toBeNull(); }); it("displays 'Sist publisert'", () => { - expect(screen.queryByText("Sist publisert:")).toBeNull(); + expect(screen.queryByText('Sist publisert:')).toBeNull(); }); }); - describe("When form is unpublished and modified date is same as or before unpublished date", () => { + describe('When form is unpublished and modified date is same as or before unpublished date', () => { const properties: PartialFormProperties = { modified: now, unpublished: now }; beforeEach(() => { render(); }); - it("modified (date) is before unpublisheddate", () => { - expect(screen.getByText("Avpublisert")).toBeInTheDocument(); + it('modified (date) is before unpublisheddate', () => { + expect(screen.getByText('Avpublisert')).toBeInTheDocument(); }); }); - describe("When form is unpublished and modified date is after unpublished date", () => { + describe('When form is unpublished and modified date is after unpublished date', () => { const properties: PartialFormProperties = { modified: now, unpublished: earlier }; beforeEach(() => { render(); }); - it("modified (date) is after unpublisheddate", () => { - expect(screen.getByText("Utkast")).toBeInTheDocument(); + it('modified (date) is after unpublisheddate', () => { + expect(screen.getByText('Utkast')).toBeInTheDocument(); }); }); - describe("Prop publishedLanguages (array)", () => { - it("displays nothing if form is not publised", () => { + describe('Prop publishedLanguages (array)', () => { + it('displays nothing if form is not publised', () => { render(); - expect(screen.queryByText("Publiserte språk:")).not.toBeInTheDocument(); + expect(screen.queryByText('Publiserte språk:')).not.toBeInTheDocument(); }); - it("displays nothing if publishedLanguages is undefined", () => { + it('displays nothing if publishedLanguages is undefined', () => { const formProps = { published: now, publishedLanguages: undefined } as FormPropertiesType; render(); - expect(screen.queryByText("Publiserte språk:")).not.toBeInTheDocument(); + expect(screen.queryByText('Publiserte språk:')).not.toBeInTheDocument(); }); - it("displays bokmål if publishedLanguages is empty", () => { + it('displays bokmål if publishedLanguages is empty', () => { const formProps = { published: now, publishedLanguages: [] as string[], } as FormPropertiesType; render(); - expect(screen.queryByText("Publiserte språk:")).toBeInTheDocument(); - expect(screen.queryByText(allLanguagesInNorwegian["nb-NO"])).toBeInTheDocument(); + expect(screen.queryByText('Publiserte språk:')).toBeInTheDocument(); + expect(screen.queryByText(allLanguagesInNorwegian['nb-NO'])).toBeInTheDocument(); }); - it("displays all published languages + bokmål", () => { - const publishedLanguages = ["en", "nn-NO"]; + it('displays all published languages + bokmål', () => { + const publishedLanguages = ['en', 'nn-NO']; const formProps = { published: now, publishedLanguages, } as FormPropertiesType; render(); - expect(screen.queryByText("Publiserte språk:")).toBeInTheDocument(); - expect(screen.queryByText(allLanguagesInNorwegian["nb-NO"])).toBeInTheDocument(); + expect(screen.queryByText('Publiserte språk:')).toBeInTheDocument(); + expect(screen.queryByText(allLanguagesInNorwegian['nb-NO'])).toBeInTheDocument(); publishedLanguages.forEach((langCode) => { expect(screen.queryByText(allLanguagesInNorwegian[langCode])).toBeInTheDocument(); }); }); }); - describe("When form has status test", () => { + describe('When form has status test', () => { const properties: PartialFormProperties = { modified: now, published: earlier, isTestForm: true }; beforeEach(() => { @@ -165,19 +165,19 @@ describe("FormStatusPanel", () => { }); it("displays the 'Testskjema' status even if published and modified is set", () => { - expect(screen.getByText("Testskjema")).toBeInTheDocument(); + expect(screen.getByText('Testskjema')).toBeInTheDocument(); }); }); - describe("Toggle diff button", () => { + describe('Toggle diff button', () => { let setDiffOn; beforeEach(() => { setDiffOn = vi.fn(); }); - describe("feature toggle enableDiff is true", () => { - describe("form is published", () => { + describe('feature toggle enableDiff is true', () => { + describe('form is published', () => { it("button text is 'Skjul' when diffOn is true", () => { const properties: PartialFormProperties = { modified: now, published: earlier }; render( @@ -185,7 +185,7 @@ describe("FormStatusPanel", () => { , ); - expect(screen.queryByRole("button", { name: "Skjul endringer" })).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Skjul endringer' })).toBeInTheDocument(); }); it("button text is 'Vis' when diffOn is false", () => { @@ -195,32 +195,32 @@ describe("FormStatusPanel", () => { , ); - expect(screen.queryByRole("button", { name: "Vis endringer" })).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Vis endringer' })).toBeInTheDocument(); }); }); - describe("form is not published", () => { - it("is not visible when form is not published", () => { + describe('form is not published', () => { + it('is not visible when form is not published', () => { const properties: PartialFormProperties = { modified: earlier, published: undefined }; render( , ); - expect(screen.queryByRole("button", { name: "Skjul endringer" })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Skjul endringer' })).not.toBeInTheDocument(); }); }); }); - it("feature toggle enableDiff is false", () => { + it('feature toggle enableDiff is false', () => { const properties: PartialFormProperties = { modified: now, published: earlier }; render( , ); - expect(screen.queryByRole("button", { name: "Skjul endringer" })).not.toBeInTheDocument(); - expect(screen.queryByRole("button", { name: "Vis endringer" })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Skjul endringer' })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Vis endringer' })).not.toBeInTheDocument(); }); }); }); diff --git a/packages/bygger/src/Forms/status/FormStatusPanel.tsx b/packages/bygger/src/Forms/status/FormStatusPanel.tsx index 53f352c6e..6dcb161bc 100644 --- a/packages/bygger/src/Forms/status/FormStatusPanel.tsx +++ b/packages/bygger/src/Forms/status/FormStatusPanel.tsx @@ -1,14 +1,14 @@ -import { Label, Panel } from "@navikt/ds-react"; -import FormStatus, { determineStatus } from "./FormStatus"; -import PublishedLanguages from "./PublishedLanguages"; -import Timestamp from "./Timestamp"; -import ToggleDiffButton from "./ToggleDiffButton"; -import { useStatusStyles } from "./styles"; -import { PublishProperties } from "./types"; +import { Label, Panel } from '@navikt/ds-react'; +import FormStatus, { determineStatus } from './FormStatus'; +import PublishedLanguages from './PublishedLanguages'; +import Timestamp from './Timestamp'; +import ToggleDiffButton from './ToggleDiffButton'; +import { useStatusStyles } from './styles'; +import { PublishProperties } from './types'; interface Props { publishProperties: PublishProperties; - spacing?: "default" | "small"; + spacing?: 'default' | 'small'; hideToggleDiffButton?: boolean; } diff --git a/packages/bygger/src/Forms/status/PublishedLanguages.tsx b/packages/bygger/src/Forms/status/PublishedLanguages.tsx index 9cebc7c13..259c30b0f 100644 --- a/packages/bygger/src/Forms/status/PublishedLanguages.tsx +++ b/packages/bygger/src/Forms/status/PublishedLanguages.tsx @@ -1,12 +1,12 @@ -import { Label } from "@navikt/ds-react"; -import { languagesInNorwegian } from "../../context/i18n"; -import { useStatusStyles } from "./styles"; -import { PublishProperties } from "./types"; +import { Label } from '@navikt/ds-react'; +import { languagesInNorwegian } from '../../context/i18n'; +import { useStatusStyles } from './styles'; +import { PublishProperties } from './types'; -const langCodeBokmal = "nb-NO"; +const langCodeBokmal = 'nb-NO'; export const allLanguagesInNorwegian = { ...languagesInNorwegian, - [langCodeBokmal]: "Norsk bokmål", + [langCodeBokmal]: 'Norsk bokmål', }; interface Props { diff --git a/packages/bygger/src/Forms/status/Timestamp.tsx b/packages/bygger/src/Forms/status/Timestamp.tsx index 5004d5ca4..391ac7add 100644 --- a/packages/bygger/src/Forms/status/Timestamp.tsx +++ b/packages/bygger/src/Forms/status/Timestamp.tsx @@ -1,5 +1,5 @@ -import moment from "moment"; -import { useStatusStyles } from "./styles"; +import moment from 'moment'; +import { useStatusStyles } from './styles'; const Timestamp = ({ timestamp }: { timestamp?: string }) => { const styles = useStatusStyles({}); @@ -8,7 +8,7 @@ const Timestamp = ({ timestamp }: { timestamp?: string }) => { } const timestampAsMoment = moment(timestamp); - const dateAndTime = `${timestampAsMoment.format("DD.MM.YY")}, kl. ${timestampAsMoment.format("HH.mm")}`; + const dateAndTime = `${timestampAsMoment.format('DD.MM.YY')}, kl. ${timestampAsMoment.format('HH.mm')}`; return

      {dateAndTime}

      ; }; diff --git a/packages/bygger/src/Forms/status/ToggleDiffButton.tsx b/packages/bygger/src/Forms/status/ToggleDiffButton.tsx index a1c2e283f..cbdbb232d 100644 --- a/packages/bygger/src/Forms/status/ToggleDiffButton.tsx +++ b/packages/bygger/src/Forms/status/ToggleDiffButton.tsx @@ -1,13 +1,12 @@ -import { Button } from "@navikt/ds-react"; -import { useAppConfig } from "@navikt/skjemadigitalisering-shared-components"; -import React from "react"; +import { Button } from '@navikt/ds-react'; +import { useAppConfig } from '@navikt/skjemadigitalisering-shared-components'; const ToggleDiffButton = ({ className }) => { const { diffOn, setDiffOn, featureToggles } = useAppConfig(); if (featureToggles?.enableDiff && setDiffOn) { return ( ); } diff --git a/packages/bygger/src/Forms/status/styles.ts b/packages/bygger/src/Forms/status/styles.ts index a914ad044..f1986292a 100644 --- a/packages/bygger/src/Forms/status/styles.ts +++ b/packages/bygger/src/Forms/status/styles.ts @@ -1,58 +1,58 @@ -import { makeStyles } from "@navikt/skjemadigitalisering-shared-components"; -import { StreetLightSize } from "./types"; +import { makeStyles } from '@navikt/skjemadigitalisering-shared-components'; +import { StreetLightSize } from './types'; const useStatusStyles = makeStyles({ container: { - display: "flex", - flexDirection: "column", + display: 'flex', + flexDirection: 'column', }, statusRow: { - display: "flex", - flexDirection: "row", - alignItems: "center", + display: 'flex', + flexDirection: 'row', + alignItems: 'center', }, toggleDiffButton: { - marginTop: "0.5rem", - minWidth: "1rem", + marginTop: '0.5rem', + minWidth: '1rem', }, rowText: { - flex: "1", - margin: "0", + flex: '1', + margin: '0', }, panelItem: ({ spacing }: { spacing?: string }) => ({ - "&:not(:last-child)": { - marginBottom: spacing && spacing === "small" ? "1rem" : "2.5rem", + '&:not(:last-child)': { + marginBottom: spacing && spacing === 'small' ? '1rem' : '2.5rem', }, }), sidePanelFormStatusContainer: { - marginTop: "0.5rem", + marginTop: '0.5rem', }, }); const useFormStatusIndicatorStyles = makeStyles({ streetLight: (props: { size: StreetLightSize }) => ({ - width: props.size === "small" ? "1rem" : "1.5rem", - maxWidth: props.size === "small" ? "1rem" : "1.5rem", - height: props.size === "small" ? "1rem" : "1.5rem", - borderRadius: "50%", - marginRight: "0.75rem", - flex: "1", + width: props.size === 'small' ? '1rem' : '1.5rem', + maxWidth: props.size === 'small' ? '1rem' : '1.5rem', + height: props.size === 'small' ? '1rem' : '1.5rem', + borderRadius: '50%', + marginRight: '0.75rem', + flex: '1', }), published: { - backgroundColor: "#219653", + backgroundColor: '#219653', }, pending: { - backgroundColor: "rgb(255, 145, 0)", + backgroundColor: 'rgb(255, 145, 0)', }, draft: { - backgroundColor: "#2D9CDB", + backgroundColor: '#2D9CDB', }, unpublished: { - backgroundColor: "#AA5EEB", + backgroundColor: '#AA5EEB', }, testform: { - backgroundColor: "#EB5757", + backgroundColor: '#EB5757', }, }); -export { useStatusStyles, useFormStatusIndicatorStyles }; +export { useFormStatusIndicatorStyles, useStatusStyles }; diff --git a/packages/bygger/src/Forms/status/types.d.ts b/packages/bygger/src/Forms/status/types.d.ts index e1958c253..130e653ae 100644 --- a/packages/bygger/src/Forms/status/types.d.ts +++ b/packages/bygger/src/Forms/status/types.d.ts @@ -1,10 +1,10 @@ -import { FormPropertiesType } from "@navikt/skjemadigitalisering-shared-domain"; +import { FormPropertiesType } from '@navikt/skjemadigitalisering-shared-domain'; -export type Status = "PENDING" | "DRAFT" | "PUBLISHED" | "UNKNOWN" | "TESTFORM" | "UNPUBLISHED"; +export type Status = 'PENDING' | 'DRAFT' | 'PUBLISHED' | 'UNKNOWN' | 'TESTFORM' | 'UNPUBLISHED'; -export type StreetLightSize = "small" | "large"; +export type StreetLightSize = 'small' | 'large'; -export type PublishStatusProperties = Pick; +export type PublishStatusProperties = Pick; export type PublishProperties = PublishStatusProperties & - Pick; + Pick; diff --git a/packages/bygger/src/Forms/unpublish/ConfirmUnpublishModal.tsx b/packages/bygger/src/Forms/unpublish/ConfirmUnpublishModal.tsx index 5e7e1e461..3de8e0d07 100644 --- a/packages/bygger/src/Forms/unpublish/ConfirmUnpublishModal.tsx +++ b/packages/bygger/src/Forms/unpublish/ConfirmUnpublishModal.tsx @@ -1,7 +1,7 @@ -import { BodyShort, Button } from "@navikt/ds-react"; -import { Modal } from "@navikt/skjemadigitalisering-shared-components"; -import { NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; -import { useState } from "react"; +import { BodyShort, Button } from '@navikt/ds-react'; +import { Modal } from '@navikt/skjemadigitalisering-shared-components'; +import { NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; +import { useState } from 'react'; interface Props { openModal: boolean; diff --git a/packages/bygger/src/Forms/unpublish/UnpublishButton.test.tsx b/packages/bygger/src/Forms/unpublish/UnpublishButton.test.tsx index 6f11490ce..429546930 100644 --- a/packages/bygger/src/Forms/unpublish/UnpublishButton.test.tsx +++ b/packages/bygger/src/Forms/unpublish/UnpublishButton.test.tsx @@ -1,11 +1,11 @@ -import { Modal } from "@navikt/skjemadigitalisering-shared-components"; -import { dateUtils, NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; -import { fireEvent, render, screen } from "@testing-library/react"; -import UnpublishButton from "./UnpublishButton"; +import { Modal } from '@navikt/skjemadigitalisering-shared-components'; +import { dateUtils, NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; +import { fireEvent, render, screen } from '@testing-library/react'; +import UnpublishButton from './UnpublishButton'; -Modal.setAppElement(document.createElement("div")); +Modal.setAppElement(document.createElement('div')); -describe("UnpublishButton", () => { +describe('UnpublishButton', () => { const onUnpublish = vi.fn(); const renderButton = (form?: NavFormType) => { if (!form) { @@ -16,21 +16,21 @@ describe("UnpublishButton", () => { render(); }; - it("do not render button if not published", () => { + it('do not render button if not published', () => { renderButton({} as NavFormType); - expect(screen.queryByRole("button")).not.toBeInTheDocument(); + expect(screen.queryByRole('button')).not.toBeInTheDocument(); }); - it("renders button", async () => { + it('renders button', async () => { renderButton(); - expect(await screen.findByRole("button")).toBeInTheDocument(); + expect(await screen.findByRole('button')).toBeInTheDocument(); }); - it("click button", async () => { + it('click button', async () => { renderButton(); - const button = await screen.findByRole("button"); + const button = await screen.findByRole('button'); expect(button).toBeInTheDocument(); fireEvent.click(button); - expect(await screen.findByRole("dialog")).toBeInTheDocument(); + expect(await screen.findByRole('dialog')).toBeInTheDocument(); }); }); diff --git a/packages/bygger/src/Forms/unpublish/UnpublishButton.tsx b/packages/bygger/src/Forms/unpublish/UnpublishButton.tsx index d29ee62ec..2d9142f9d 100644 --- a/packages/bygger/src/Forms/unpublish/UnpublishButton.tsx +++ b/packages/bygger/src/Forms/unpublish/UnpublishButton.tsx @@ -1,7 +1,7 @@ -import { Button } from "@navikt/ds-react"; -import { NavFormType } from "@navikt/skjemadigitalisering-shared-domain"; -import { useModal } from "../../util/useModal"; -import ConfirmUnpublishModal from "./ConfirmUnpublishModal"; +import { Button } from '@navikt/ds-react'; +import { NavFormType } from '@navikt/skjemadigitalisering-shared-domain'; +import { useModal } from '../../util/useModal'; +import ConfirmUnpublishModal from './ConfirmUnpublishModal'; interface UnpublishButtonProps { onUnpublish: (form) => void; diff --git a/packages/bygger/src/UnauthenticatedApp.jsx b/packages/bygger/src/UnauthenticatedApp.jsx index 217b69785..ae6c6bbcb 100644 --- a/packages/bygger/src/UnauthenticatedApp.jsx +++ b/packages/bygger/src/UnauthenticatedApp.jsx @@ -1,12 +1,12 @@ -import { makeStyles, NavForm, useAppConfig } from "@navikt/skjemadigitalisering-shared-components"; -import { NavBar } from "./components/Navbar/NavBar"; -import { useAuth } from "./context/auth-context"; -import PageWrapper from "./Forms/PageWrapper"; +import { makeStyles, NavForm, useAppConfig } from '@navikt/skjemadigitalisering-shared-components'; +import { NavBar } from './components/Navbar/NavBar'; +import { useAuth } from './context/auth-context'; +import PageWrapper from './Forms/PageWrapper'; const useStyles = makeStyles({ navForm: { - margin: "0 auto", - maxWidth: "26.25rem", + margin: '0 auto', + maxWidth: '26.25rem', }, }); @@ -16,7 +16,7 @@ const UnauthenticatedApp = ({ projectURL }) => { const styles = useStyles(); return ( <> - + {config?.isDevelopment ? ( login(user)} /> diff --git a/packages/bygger/src/components/AppLayout.jsx b/packages/bygger/src/components/AppLayout.jsx index 09c44bbec..3367bcb76 100644 --- a/packages/bygger/src/components/AppLayout.jsx +++ b/packages/bygger/src/components/AppLayout.jsx @@ -1,12 +1,12 @@ -import { makeStyles, navCssVariables } from "@navikt/skjemadigitalisering-shared-components"; -import PageWrapper from "../Forms/PageWrapper"; -import { NavBar } from "./Navbar/NavBar"; +import { makeStyles, navCssVariables } from '@navikt/skjemadigitalisering-shared-components'; +import PageWrapper from '../Forms/PageWrapper'; +import { NavBar } from './Navbar/NavBar'; const useStyles = makeStyles({ noScroll: { backgroundColor: navCssVariables.navGraBakgrunn, - position: "sticky", - top: "0", + position: 'sticky', + top: '0', zIndex: 900, }, }); diff --git a/packages/bygger/src/components/FormMetaDataEditor/EnhetSettings.tsx b/packages/bygger/src/components/FormMetaDataEditor/EnhetSettings.tsx index cd9ee0746..e65b91826 100644 --- a/packages/bygger/src/components/FormMetaDataEditor/EnhetSettings.tsx +++ b/packages/bygger/src/components/FormMetaDataEditor/EnhetSettings.tsx @@ -1,7 +1,7 @@ -import { Checkbox, Label, Panel } from "@navikt/ds-react"; -import { makeStyles } from "@navikt/skjemadigitalisering-shared-components"; -import { Enhetstype, supportedEnhetstyper } from "@navikt/skjemadigitalisering-shared-domain"; -import { useEffect } from "react"; +import { Checkbox, Label, Panel } from '@navikt/ds-react'; +import { makeStyles } from '@navikt/skjemadigitalisering-shared-components'; +import { Enhetstype, supportedEnhetstyper } from '@navikt/skjemadigitalisering-shared-domain'; +import { useEffect } from 'react'; interface EnhetSettingsProps { enhetMaVelges: boolean; @@ -12,19 +12,19 @@ interface EnhetSettingsProps { const useStyles = makeStyles({ list: { - maxWidth: "100%", - maxHeight: "200px", - display: "flex", - gap: "0 1rem", - flexDirection: "column", - flexWrap: "wrap", - listStyle: "none", + maxWidth: '100%', + maxHeight: '200px', + display: 'flex', + gap: '0 1rem', + flexDirection: 'column', + flexWrap: 'wrap', + listStyle: 'none', - "@media screen and (max-width: 1080px)": { - maxHeight: "400px", + '@media screen and (max-width: 1080px)': { + maxHeight: '400px', }, - "@media screen and (max-width: 600px)": { - maxHeight: "1000px", + '@media screen and (max-width: 600px)': { + maxHeight: '1000px', }, }, }); @@ -46,7 +46,7 @@ const EnhetSettings = ({ return ( <> onChangeEnhetMaVelges(event.target.checked)}> - {"Bruker må velge enhet ved innsending på papir"} + {'Bruker må velge enhet ved innsending på papir'} {enhetMaVelges && selectedEnhetstyper && ( diff --git a/packages/bygger/src/components/FormMetaDataEditor/FormMetadataEditor.test.tsx b/packages/bygger/src/components/FormMetaDataEditor/FormMetadataEditor.test.tsx index 6b59f3358..b0c894053 100644 --- a/packages/bygger/src/components/FormMetaDataEditor/FormMetadataEditor.test.tsx +++ b/packages/bygger/src/components/FormMetaDataEditor/FormMetadataEditor.test.tsx @@ -1,17 +1,17 @@ -import { AppConfigProvider } from "@navikt/skjemadigitalisering-shared-components"; -import { FormPropertiesType, NavFormType, supportedEnhetstyper } from "@navikt/skjemadigitalisering-shared-domain"; -import { render, screen, waitFor, within } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import { v4 as uuidv4 } from "uuid"; -import form from "../../../example_data/Form.json"; -import featureToggles from "../../../test/featureToggles"; -import mockMottaksadresser from "../../fakeBackend/mock-mottaksadresser"; -import { CreationFormMetadataEditor, FormMetadataEditor } from "./FormMetadataEditor"; -import { UpdateFormFunction } from "./utils"; +import { AppConfigProvider } from '@navikt/skjemadigitalisering-shared-components'; +import { FormPropertiesType, NavFormType, supportedEnhetstyper } from '@navikt/skjemadigitalisering-shared-domain'; +import { render, screen, waitFor, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { v4 as uuidv4 } from 'uuid'; +import form from '../../../example_data/Form.json'; +import featureToggles from '../../../test/featureToggles'; +import mockMottaksadresser from '../../fakeBackend/mock-mottaksadresser'; +import { CreationFormMetadataEditor, FormMetadataEditor } from './FormMetadataEditor'; +import { UpdateFormFunction } from './utils'; const testform = form as unknown as NavFormType; -vi.mock("../../hooks/useMottaksadresser", () => { +vi.mock('../../hooks/useMottaksadresser', () => { return { default: () => ({ ready: true, @@ -20,22 +20,22 @@ vi.mock("../../hooks/useMottaksadresser", () => { }), }; }); -vi.mock("../../hooks/useTemaKoder", () => { +vi.mock('../../hooks/useTemaKoder', () => { return { default: () => ({ ready: true, temaKoder: [ - { key: "ABC", value: "Tema 1" }, - { key: "XYZ", value: "Tema 3" }, - { key: "DEF", value: "Tema 2" }, + { key: 'ABC', value: 'Tema 1' }, + { key: 'XYZ', value: 'Tema 3' }, + { key: 'DEF', value: 'Tema 2' }, ], errorMessage: undefined, }), }; }); -vi.mock("react-router-dom", async () => { - const actual = await vi.importActual("react-router-dom"); +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); return { ...actual, Link: () => testlink, @@ -43,27 +43,27 @@ vi.mock("react-router-dom", async () => { }); const defaultForm: NavFormType = { - title: "Testskjema", - name: "testskjema", - path: "tst123456", - tags: ["nav-skjema", ""], - type: "form", + title: 'Testskjema', + name: 'testskjema', + path: 'tst123456', + tags: ['nav-skjema', ''], + type: 'form', components: [], properties: { - skjemanummer: "TST 12.34-56", - innsending: "PAPIR_OG_DIGITAL", - tema: "BIL", + skjemanummer: 'TST 12.34-56', + innsending: 'PAPIR_OG_DIGITAL', + tema: 'BIL', enhetMaVelgesVedPapirInnsending: false, enhetstyper: [], signatures: [ { - label: "", - description: "", - key: "ddade517-86c6-4f1e-b730-a477e01dc245", + label: '', + description: '', + key: 'ddade517-86c6-4f1e-b730-a477e01dc245', }, ], }, - display: "wizard", + display: 'wizard', }; const formMedProps = (props: Partial): NavFormType => ({ @@ -74,23 +74,23 @@ const formMedProps = (props: Partial): NavFormType => ({ }, }); -describe("FormMetadataEditor", () => { +describe('FormMetadataEditor', () => { let mockOnChange; beforeEach(() => { mockOnChange = vi.fn(); }); - describe("Usage context: EDIT", () => { - it("should update form when title is changed", async () => { + describe('Usage context: EDIT', () => { + it('should update form when title is changed', async () => { const { rerender } = render( , ); - await userEvent.clear(screen.getByRole("textbox", { name: /Tittel/i })); - const clearedForm: NavFormType = { ...testform, title: "" }; + await userEvent.clear(screen.getByRole('textbox', { name: /Tittel/i })); + const clearedForm: NavFormType = { ...testform, title: '' }; await waitFor(() => expect(mockOnChange).toHaveBeenCalledWith(clearedForm)); rerender( @@ -98,73 +98,73 @@ describe("FormMetadataEditor", () => { , ); - await userEvent.type(screen.getByRole("textbox", { name: /Tittel/i }), "Søknad om førerhund"); - const updatedForm: NavFormType = { ...testform, title: "Søknad om førerhund" }; + await userEvent.type(screen.getByRole('textbox', { name: /Tittel/i }), 'Søknad om førerhund'); + const updatedForm: NavFormType = { ...testform, title: 'Søknad om førerhund' }; rerender( , ); - expect(screen.getByRole("textbox", { name: /Tittel/i })).toHaveValue("Søknad om førerhund"); + expect(screen.getByRole('textbox', { name: /Tittel/i })).toHaveValue('Søknad om førerhund'); }); - describe("Forklaring til innsending", () => { - it("Viser input for forklaring når innsending settes til INGEN", async () => { + describe('Forklaring til innsending', () => { + it('Viser input for forklaring når innsending settes til INGEN', async () => { const { rerender } = render(); - expect(screen.queryByLabelText("Forklaring til innsending")).toBeNull(); - await userEvent.selectOptions(screen.getByLabelText("Innsending"), "INGEN"); + expect(screen.queryByLabelText('Forklaring til innsending')).toBeNull(); + await userEvent.selectOptions(screen.getByLabelText('Innsending'), 'INGEN'); expect(mockOnChange).toHaveBeenCalled(); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.innsending).toEqual("INGEN"); + expect(updatedForm.properties.innsending).toBe('INGEN'); rerender(); - expect(screen.queryByLabelText("Forklaring til innsending")).not.toBeNull(); + expect(screen.queryByLabelText('Forklaring til innsending')).not.toBeNull(); }); - it("Input for forklaring til innsending skjules når man velger noe annet enn INGEN", async () => { + it('Input for forklaring til innsending skjules når man velger noe annet enn INGEN', async () => { const form: NavFormType = { ...defaultForm, properties: { ...defaultForm.properties, - innsending: "INGEN", + innsending: 'INGEN', }, }; const { rerender } = render(); - expect(screen.queryByLabelText("Forklaring til innsending")).not.toBeNull(); - await userEvent.selectOptions(screen.getByLabelText("Innsending"), "KUN_PAPIR"); + expect(screen.queryByLabelText('Forklaring til innsending')).not.toBeNull(); + await userEvent.selectOptions(screen.getByLabelText('Innsending'), 'KUN_PAPIR'); expect(mockOnChange).toHaveBeenCalled(); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.innsending).toEqual("KUN_PAPIR"); + expect(updatedForm.properties.innsending).toBe('KUN_PAPIR'); rerender(); - expect(screen.queryByLabelText("Forklaring til innsending")).toBeNull(); + expect(screen.queryByLabelText('Forklaring til innsending')).toBeNull(); }); }); - it("Valg av innsending=KUN_PAPIR", async () => { + it('Valg av innsending=KUN_PAPIR', async () => { const form: NavFormType = { ...defaultForm, properties: { ...defaultForm.properties, - innsending: "PAPIR_OG_DIGITAL", + innsending: 'PAPIR_OG_DIGITAL', }, }; const { rerender } = render(); - expect(screen.queryByLabelText("Forklaring til innsending")).toBeNull(); - await userEvent.selectOptions(screen.getByLabelText("Innsending"), "KUN_PAPIR"); + expect(screen.queryByLabelText('Forklaring til innsending')).toBeNull(); + await userEvent.selectOptions(screen.getByLabelText('Innsending'), 'KUN_PAPIR'); expect(mockOnChange).toHaveBeenCalled(); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.innsending).toEqual("KUN_PAPIR"); + expect(updatedForm.properties.innsending).toBe('KUN_PAPIR'); rerender(); - expect(screen.queryByLabelText("Forklaring til innsending")).toBeNull(); + expect(screen.queryByLabelText('Forklaring til innsending')).toBeNull(); }); - describe("Egendefinert tekst på knapp for nedlasting av pdf", () => { + describe('Egendefinert tekst på knapp for nedlasting av pdf', () => { const formMedDownloadPdfButtonText = (downloadPdfButtonText) => ({ ...defaultForm, properties: { @@ -173,109 +173,109 @@ describe("FormMetadataEditor", () => { }, }); - it("lagres i properties", async () => { + it('lagres i properties', async () => { const form = formMedDownloadPdfButtonText(undefined); render(); - const input = screen.getByLabelText("Tekst på knapp for nedlasting av pdf"); + const input = screen.getByLabelText('Tekst på knapp for nedlasting av pdf'); await userEvent.click(input); - await userEvent.paste("Last ned pdf"); + await userEvent.paste('Last ned pdf'); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.downloadPdfButtonText).toEqual("Last ned pdf"); + expect(updatedForm.properties.downloadPdfButtonText).toBe('Last ned pdf'); }); - it("nullstilles i properties", async () => { - const form = formMedDownloadPdfButtonText("Last meg ned"); + it('nullstilles i properties', async () => { + const form = formMedDownloadPdfButtonText('Last meg ned'); render(); - const input = screen.getByLabelText("Tekst på knapp for nedlasting av pdf"); + const input = screen.getByLabelText('Tekst på knapp for nedlasting av pdf'); await userEvent.clear(input); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.downloadPdfButtonText).toEqual(""); + expect(updatedForm.properties.downloadPdfButtonText).toBe(''); }); }); - describe("Ettersendelsesfrist", () => { - it("lagres i properties", async () => { - const form = formMedProps({ ettersendelsesfrist: undefined, ettersending: "KUN_DIGITAL" }); + describe('Ettersendelsesfrist', () => { + it('lagres i properties', async () => { + const form = formMedProps({ ettersendelsesfrist: undefined, ettersending: 'KUN_DIGITAL' }); render(); - const input = screen.getByLabelText("Ettersendelsesfrist (dager)"); + const input = screen.getByLabelText('Ettersendelsesfrist (dager)'); await userEvent.click(input); - await userEvent.paste("42"); + await userEvent.paste('42'); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.ettersendelsesfrist).toEqual("42"); + expect(updatedForm.properties.ettersendelsesfrist).toBe('42'); }); - it("nullstilles i properties", async () => { - const form = formMedProps({ ettersendelsesfrist: "42", ettersending: "KUN_DIGITAL" }); + it('nullstilles i properties', async () => { + const form = formMedProps({ ettersendelsesfrist: '42', ettersending: 'KUN_DIGITAL' }); render(); - const input = screen.getByLabelText("Ettersendelsesfrist (dager)"); + const input = screen.getByLabelText('Ettersendelsesfrist (dager)'); await userEvent.clear(input); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.ettersendelsesfrist).toEqual(""); + expect(updatedForm.properties.ettersendelsesfrist).toBe(''); }); }); - describe("Mottaksadresse", () => { - describe("Dropdown med mottaksadresser", () => { - it("Vises ikke når innsending=INGEN", async () => { - const form: NavFormType = formMedProps({ innsending: "INGEN" }); + describe('Mottaksadresse', () => { + describe('Dropdown med mottaksadresser', () => { + it('Vises ikke når innsending=INGEN', async () => { + const form: NavFormType = formMedProps({ innsending: 'INGEN' }); render(); - expect(screen.queryByLabelText("Mottaksadresse")).toBeFalsy(); + expect(screen.queryByLabelText('Mottaksadresse')).toBeFalsy(); }); - it("Vises ikke når innsending=KUN_DIGITAL", async () => { - const form: NavFormType = formMedProps({ innsending: "KUN_DIGITAL" }); + it('Vises ikke når innsending=KUN_DIGITAL', async () => { + const form: NavFormType = formMedProps({ innsending: 'KUN_DIGITAL' }); render(); - expect(screen.queryByLabelText("Mottaksadresse")).toBeFalsy(); + expect(screen.queryByLabelText('Mottaksadresse')).toBeFalsy(); }); - it("Vises når innsending=KUN_PAPIR", async () => { - const form: NavFormType = formMedProps({ innsending: "KUN_PAPIR" }); + it('Vises når innsending=KUN_PAPIR', async () => { + const form: NavFormType = formMedProps({ innsending: 'KUN_PAPIR' }); render(); - expect(screen.queryByLabelText("Mottaksadresse")).toBeTruthy(); + expect(screen.queryByLabelText('Mottaksadresse')).toBeTruthy(); }); - it("Vises når innsending=PAPIR_OG_DIGITAL", async () => { - const form: NavFormType = formMedProps({ innsending: "PAPIR_OG_DIGITAL" }); + it('Vises når innsending=PAPIR_OG_DIGITAL', async () => { + const form: NavFormType = formMedProps({ innsending: 'PAPIR_OG_DIGITAL' }); render(); - expect(screen.queryByLabelText("Mottaksadresse")).toBeTruthy(); + expect(screen.queryByLabelText('Mottaksadresse')).toBeTruthy(); }); - it("Vises når innsending=undefined", async () => { + it('Vises når innsending=undefined', async () => { const form: NavFormType = formMedProps({ innsending: undefined }); render(); - expect(screen.queryByLabelText("Mottaksadresse")).toBeTruthy(); + expect(screen.queryByLabelText('Mottaksadresse')).toBeTruthy(); }); - it("Viser valgt mottaksadresse med formattering", async () => { - const form: NavFormType = formMedProps({ mottaksadresseId: "1" }); + it('Viser valgt mottaksadresse med formattering', async () => { + const form: NavFormType = formMedProps({ mottaksadresseId: '1' }); render(); - expect(screen.getByDisplayValue("NAV alternativ skanning, Postboks 3, 0591 Oslo")).toBeTruthy(); + expect(screen.getByDisplayValue('NAV alternativ skanning, Postboks 3, 0591 Oslo')).toBeTruthy(); }); }); - describe("Endring av mottaksadresse", () => { - it("Setter ny mottaksadresse", async () => { + describe('Endring av mottaksadresse', () => { + it('Setter ny mottaksadresse', async () => { const form: NavFormType = formMedProps({ mottaksadresseId: undefined }); render(); - await userEvent.selectOptions(screen.getByLabelText("Mottaksadresse"), "1"); + await userEvent.selectOptions(screen.getByLabelText('Mottaksadresse'), '1'); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.mottaksadresseId).toEqual("1"); + expect(updatedForm.properties.mottaksadresseId).toBe('1'); }); - it("Fjerner valgt mottaksadresse", async () => { - const form: NavFormType = formMedProps({ mottaksadresseId: "1" }); + it('Fjerner valgt mottaksadresse', async () => { + const form: NavFormType = formMedProps({ mottaksadresseId: '1' }); render(); - await userEvent.selectOptions(screen.getByLabelText("Mottaksadresse"), ""); + await userEvent.selectOptions(screen.getByLabelText('Mottaksadresse'), ''); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; @@ -284,45 +284,45 @@ describe("FormMetadataEditor", () => { }); }); - describe("Innstilling for valg av enhet ved papirinnsending", () => { - const expectedCheckboxName = "Bruker må velge enhet ved innsending på papir"; + describe('Innstilling for valg av enhet ved papirinnsending', () => { + const expectedCheckboxName = 'Bruker må velge enhet ved innsending på papir'; const editFormMetadataEditor = (form: NavFormType, onChange: UpdateFormFunction) => ( ); - it("Vises når innsending=KUN_PAPIR", async () => { + it('Vises når innsending=KUN_PAPIR', async () => { const form: NavFormType = formMedProps({ - innsending: "KUN_PAPIR", + innsending: 'KUN_PAPIR', mottaksadresseId: undefined, }); render(editFormMetadataEditor(form, mockOnChange)); - expect(screen.queryByRole("checkbox", { name: expectedCheckboxName })).toBeTruthy(); + expect(screen.queryByRole('checkbox', { name: expectedCheckboxName })).toBeTruthy(); }); - it("Vises når innsending=PAPIR_OG_DIGITAL", async () => { - const form: NavFormType = formMedProps({ innsending: "PAPIR_OG_DIGITAL" }); + it('Vises når innsending=PAPIR_OG_DIGITAL', async () => { + const form: NavFormType = formMedProps({ innsending: 'PAPIR_OG_DIGITAL' }); render(editFormMetadataEditor(form, mockOnChange)); - expect(screen.queryByRole("checkbox", { name: expectedCheckboxName })).toBeTruthy(); + expect(screen.queryByRole('checkbox', { name: expectedCheckboxName })).toBeTruthy(); }); - it("Vises ikke når innsending=INGEN", async () => { - const form: NavFormType = formMedProps({ innsending: "INGEN" }); + it('Vises ikke når innsending=INGEN', async () => { + const form: NavFormType = formMedProps({ innsending: 'INGEN' }); render(editFormMetadataEditor(form, mockOnChange)); - expect(screen.queryByRole("checkbox", { name: expectedCheckboxName })).toBeFalsy(); + expect(screen.queryByRole('checkbox', { name: expectedCheckboxName })).toBeFalsy(); }); - it("Vises ikke når innsending=KUN_DIGITAL", async () => { - const form: NavFormType = formMedProps({ innsending: "KUN_DIGITAL" }); + it('Vises ikke når innsending=KUN_DIGITAL', async () => { + const form: NavFormType = formMedProps({ innsending: 'KUN_DIGITAL' }); render(editFormMetadataEditor(form, mockOnChange)); - expect(screen.queryByRole("checkbox", { name: expectedCheckboxName })).toBeFalsy(); + expect(screen.queryByRole('checkbox', { name: expectedCheckboxName })).toBeFalsy(); }); - it("Kan endres til true ved klikk på checkbox", async () => { + it('Kan endres til true ved klikk på checkbox', async () => { const form: NavFormType = formMedProps({ mottaksadresseId: undefined, enhetMaVelgesVedPapirInnsending: false }); const { rerender } = render(editFormMetadataEditor(form, mockOnChange)); - let checkbox = screen.getByRole("checkbox", { + let checkbox = screen.getByRole('checkbox', { name: expectedCheckboxName, }); expect(checkbox).not.toBeChecked(); @@ -333,16 +333,16 @@ describe("FormMetadataEditor", () => { expect(updatedForm.properties.enhetMaVelgesVedPapirInnsending).toBe(true); rerender(editFormMetadataEditor(updatedForm, mockOnChange)); - checkbox = screen.getByRole("checkbox", { + checkbox = screen.getByRole('checkbox', { name: expectedCheckboxName, }); expect(checkbox).toBeChecked(); }); - it("Kan endres til false ved klikk på checkbox", async () => { + it('Kan endres til false ved klikk på checkbox', async () => { const form: NavFormType = formMedProps({ mottaksadresseId: undefined, enhetMaVelgesVedPapirInnsending: true }); const { rerender } = render(editFormMetadataEditor(form, mockOnChange)); - let checkbox = screen.getByRole("checkbox", { + let checkbox = screen.getByRole('checkbox', { name: expectedCheckboxName, }); expect(checkbox).toBeChecked(); @@ -353,50 +353,50 @@ describe("FormMetadataEditor", () => { expect(updatedForm.properties.enhetMaVelgesVedPapirInnsending).toBe(false); rerender(editFormMetadataEditor(updatedForm, mockOnChange)); - checkbox = screen.getByRole("checkbox", { + checkbox = screen.getByRole('checkbox', { name: expectedCheckboxName, }); expect(checkbox).not.toBeChecked(); }); - it("huker av checkboxer for valgte enhetstyper", () => { + it('huker av checkboxer for valgte enhetstyper', () => { const form: NavFormType = formMedProps({ mottaksadresseId: undefined, enhetMaVelgesVedPapirInnsending: true, - enhetstyper: ["ALS", "KO", "LOKAL"], + enhetstyper: ['ALS', 'KO', 'LOKAL'], }); render(editFormMetadataEditor(form, mockOnChange)); - const checkboxes = screen.getAllByRole("checkbox", { checked: true }); + const checkboxes = screen.getAllByRole('checkbox', { checked: true }); expect(checkboxes).toHaveLength(4); }); - it("fjerner valgt enhet ved klikk", async () => { + it('fjerner valgt enhet ved klikk', async () => { const form: NavFormType = formMedProps({ mottaksadresseId: undefined, enhetMaVelgesVedPapirInnsending: true, - enhetstyper: ["ALS", "KO", "LOKAL"], + enhetstyper: ['ALS', 'KO', 'LOKAL'], }); render(editFormMetadataEditor(form, mockOnChange)); - await userEvent.click(screen.getByRole("checkbox", { name: "LOKAL" })); + await userEvent.click(screen.getByRole('checkbox', { name: 'LOKAL' })); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.enhetstyper).toEqual(["ALS", "KO"]); + expect(updatedForm.properties.enhetstyper).toEqual(['ALS', 'KO']); }); - it("legger til ny valgt enhet ved klikk", async () => { + it('legger til ny valgt enhet ved klikk', async () => { const form: NavFormType = formMedProps({ mottaksadresseId: undefined, enhetMaVelgesVedPapirInnsending: true, - enhetstyper: ["ALS", "KO", "LOKAL"], + enhetstyper: ['ALS', 'KO', 'LOKAL'], }); render(editFormMetadataEditor(form, mockOnChange)); - await userEvent.click(screen.getByRole("checkbox", { name: "ARK" })); + await userEvent.click(screen.getByRole('checkbox', { name: 'ARK' })); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.enhetstyper).toEqual(["ALS", "KO", "LOKAL", "ARK"]); + expect(updatedForm.properties.enhetstyper).toEqual(['ALS', 'KO', 'LOKAL', 'ARK']); }); - it("oppdaterer skjemaet med alle støttede enheter hvis enhetstyper er undefined", () => { + it('oppdaterer skjemaet med alle støttede enheter hvis enhetstyper er undefined', () => { const props = { mottaksadresseId: undefined, enhetMaVelgesVedPapirInnsending: true, @@ -408,160 +408,160 @@ describe("FormMetadataEditor", () => { expect(mockOnChange).toHaveBeenCalledWith(formMedProps({ ...props, enhetstyper: supportedEnhetstyper })); }); - it("Nullstilles og skjules når mottaksadresse velges", async () => { + it('Nullstilles og skjules når mottaksadresse velges', async () => { const form: NavFormType = formMedProps({ mottaksadresseId: undefined, enhetMaVelgesVedPapirInnsending: true }); const { rerender } = render(editFormMetadataEditor(form, mockOnChange)); - await userEvent.selectOptions(screen.getByLabelText("Mottaksadresse"), "1"); + await userEvent.selectOptions(screen.getByLabelText('Mottaksadresse'), '1'); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.mottaksadresseId).toEqual("1"); + expect(updatedForm.properties.mottaksadresseId).toBe('1'); expect(updatedForm.properties.enhetMaVelgesVedPapirInnsending).toBe(false); rerender(editFormMetadataEditor(updatedForm, mockOnChange)); - expect(screen.queryByRole("checkbox", { name: expectedCheckboxName })).toBeFalsy(); + expect(screen.queryByRole('checkbox', { name: expectedCheckboxName })).toBeFalsy(); }); - it("Er skjult når mottaksadresse er valgt", () => { - const form: NavFormType = formMedProps({ mottaksadresseId: "1", enhetMaVelgesVedPapirInnsending: true }); + it('Er skjult når mottaksadresse er valgt', () => { + const form: NavFormType = formMedProps({ mottaksadresseId: '1', enhetMaVelgesVedPapirInnsending: true }); render(editFormMetadataEditor(form, mockOnChange)); - expect(screen.queryByRole("checkbox", { name: expectedCheckboxName })).toBeFalsy(); + expect(screen.queryByRole('checkbox', { name: expectedCheckboxName })).toBeFalsy(); }); }); - describe("Signaturer", () => { + describe('Signaturer', () => { let form: NavFormType; beforeEach(() => { form = formMedProps({}); }); - it("Legger til signatur", async () => { + it('Legger til signatur', async () => { render(); - const signaturFieldsets = screen.getAllByTestId("signatures"); + const signaturFieldsets = screen.getAllByTestId('signatures'); expect(signaturFieldsets).toHaveLength(1); - const input = within(signaturFieldsets[0]).getByLabelText("Hvem skal signere?"); + const input = within(signaturFieldsets[0]).getByLabelText('Hvem skal signere?'); await userEvent.click(input); - await userEvent.paste("Lege"); + await userEvent.paste('Lege'); expect(mockOnChange).toHaveBeenCalled(); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.signatures?.[0].label).toEqual("Lege"); + expect(updatedForm.properties.signatures?.[0].label).toBe('Lege'); }); it("legger til ny signatur ved klikk på 'legg til signatur' knapp", async () => { render(); - const knapp = screen.getByRole("button", { name: "Legg til signatur" }); + const knapp = screen.getByRole('button', { name: 'Legg til signatur' }); await userEvent.click(knapp); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.signatures?.[0].label).toEqual(""); - expect(updatedForm.properties.signatures?.[0].description).toEqual(""); + expect(updatedForm.properties.signatures?.[0].label).toBe(''); + expect(updatedForm.properties.signatures?.[0].description).toBe(''); }); - it("Slett en signatur", async () => { + it('Slett en signatur', async () => { const multipleSignatures = [ { - label: "Doctor", - description: "Doctor Description", - key: "0", + label: 'Doctor', + description: 'Doctor Description', + key: '0', }, { - label: "Test", - description: "Test Description", - key: "1", + label: 'Test', + description: 'Test Description', + key: '1', }, { - label: "Applicant", - description: "Applicant Description", - key: "2", + label: 'Applicant', + description: 'Applicant Description', + key: '2', }, ]; form = formMedProps({ signatures: multipleSignatures }); render(); - const signaturFieldsets = screen.getAllByTestId("signatures"); + const signaturFieldsets = screen.getAllByTestId('signatures'); expect(signaturFieldsets).toHaveLength(3); - const lukkKnapp = screen.getByRole("button", { name: "Slett signatur 2" }); + const lukkKnapp = screen.getByRole('button', { name: 'Slett signatur 2' }); await userEvent.click(lukkKnapp); expect(mockOnChange).toHaveBeenCalled(); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.signatures?.[0].label).toEqual("Doctor"); - expect(updatedForm.properties.signatures?.[0].description).toEqual("Doctor Description"); - expect(updatedForm.properties.signatures?.[1].label).toEqual("Applicant"); - expect(updatedForm.properties.signatures?.[1].description).toEqual("Applicant Description"); + expect(updatedForm.properties.signatures?.[0].label).toBe('Doctor'); + expect(updatedForm.properties.signatures?.[0].description).toBe('Doctor Description'); + expect(updatedForm.properties.signatures?.[1].label).toBe('Applicant'); + expect(updatedForm.properties.signatures?.[1].description).toBe('Applicant Description'); }); - it("Legger til beskrivelse for en signatur", async () => { - form = formMedProps({ signatures: [{ label: "Lege", key: "0000" }] }); + it('Legger til beskrivelse for en signatur', async () => { + form = formMedProps({ signatures: [{ label: 'Lege', key: '0000' }] }); render(); - const signature1Description = screen.getAllByRole("textbox", { name: "Instruksjoner til den som signerer" })[0]; + const signature1Description = screen.getAllByRole('textbox', { name: 'Instruksjoner til den som signerer' })[0]; await userEvent.click(signature1Description); - await userEvent.paste("Jeg bekrefter at personen er syk"); + await userEvent.paste('Jeg bekrefter at personen er syk'); expect(mockOnChange).toHaveBeenCalled(); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.signatures?.[0].description).toEqual("Jeg bekrefter at personen er syk"); - expect(updatedForm.properties.signatures?.[0].label).toEqual("Lege"); + expect(updatedForm.properties.signatures?.[0].description).toBe('Jeg bekrefter at personen er syk'); + expect(updatedForm.properties.signatures?.[0].label).toBe('Lege'); }); }); - describe("Beskrivelse av alle signaturene", () => { - it("settes i properties når tekst legges inn i tekstfelt", async () => { - const form: NavFormType = formMedProps({ signatures: [{ label: "Lege", key: uuidv4() }] }); + describe('Beskrivelse av alle signaturene', () => { + it('settes i properties når tekst legges inn i tekstfelt', async () => { + const form: NavFormType = formMedProps({ signatures: [{ label: 'Lege', key: uuidv4() }] }); render(); - const input = screen.getByLabelText("Generelle instruksjoner (valgfritt)"); + const input = screen.getByLabelText('Generelle instruksjoner (valgfritt)'); await userEvent.click(input); - await userEvent.paste("Lang beskrivelse av hvorfor man signerer"); + await userEvent.paste('Lang beskrivelse av hvorfor man signerer'); expect(mockOnChange).toHaveBeenCalled(); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.descriptionOfSignatures).toEqual("Lang beskrivelse av hvorfor man signerer"); + expect(updatedForm.properties.descriptionOfSignatures).toBe('Lang beskrivelse av hvorfor man signerer'); }); }); }); - describe("Usage context: CREATE", () => { - describe("Tema", () => { - it("lister ut temaer", () => { + describe('Usage context: CREATE', () => { + describe('Tema', () => { + it('lister ut temaer', () => { render(); - const temaSelect = screen.getByRole("combobox", { name: "Tema" }); - const options = within(temaSelect).queryAllByRole("option"); + const temaSelect = screen.getByRole('combobox', { name: 'Tema' }); + const options = within(temaSelect).queryAllByRole('option'); expect(options).toHaveLength(4); - expect(options[1]).toHaveTextContent("Tema 1 (ABC)"); - expect(options[2]).toHaveTextContent("Tema 3 (XYZ)"); - expect(options[3]).toHaveTextContent("Tema 2 (DEF)"); + expect(options[1]).toHaveTextContent('Tema 1 (ABC)'); + expect(options[2]).toHaveTextContent('Tema 3 (XYZ)'); + expect(options[3]).toHaveTextContent('Tema 2 (DEF)'); }); - it("setter valgt tema hvis temakoden finnes blant valgene", () => { - const form = formMedProps({ tema: "DEF" }); + it('setter valgt tema hvis temakoden finnes blant valgene', () => { + const form = formMedProps({ tema: 'DEF' }); render(); - expect(screen.getByRole("combobox", { name: "Tema" })).toHaveValue("DEF"); + expect(screen.getByRole('combobox', { name: 'Tema' })).toHaveValue('DEF'); }); - it("setter valg til default verdi hvis temakoden ikke eksisterer", () => { - const form = formMedProps({ tema: "JKL" }); + it('setter valg til default verdi hvis temakoden ikke eksisterer', () => { + const form = formMedProps({ tema: 'JKL' }); render(); - expect(screen.getByRole("combobox", { name: "Tema" })).toHaveValue(""); + expect(screen.getByRole('combobox', { name: 'Tema' })).toHaveValue(''); }); - it("oppdaterer skjema når bruker velger et nytt tema", async () => { - const form: NavFormType = formMedProps({ tema: "ABC" }); + it('oppdaterer skjema når bruker velger et nytt tema', async () => { + const form: NavFormType = formMedProps({ tema: 'ABC' }); render(); - await userEvent.selectOptions(screen.getByRole("combobox", { name: "Tema" }), "XYZ"); + await userEvent.selectOptions(screen.getByRole('combobox', { name: 'Tema' }), 'XYZ'); expect(mockOnChange).toHaveBeenCalledTimes(1); const updatedForm = mockOnChange.mock.calls[0][0] as NavFormType; - expect(updatedForm.properties.tema).toEqual("XYZ"); + expect(updatedForm.properties.tema).toBe('XYZ'); }); }); }); diff --git a/packages/bygger/src/components/FormMetaDataEditor/FormMetadataEditor.tsx b/packages/bygger/src/components/FormMetaDataEditor/FormMetadataEditor.tsx index 714778330..38abee285 100644 --- a/packages/bygger/src/components/FormMetaDataEditor/FormMetadataEditor.tsx +++ b/packages/bygger/src/components/FormMetaDataEditor/FormMetadataEditor.tsx @@ -1,13 +1,13 @@ -import { Alert, Fieldset, Textarea, TextField } from "@navikt/ds-react"; -import { formDiffingTool, NavFormType, TEXTS, UsageContext } from "@navikt/skjemadigitalisering-shared-domain"; -import AddressFields from "./fields/AddressFields"; -import BasicFields from "./fields/BasicFields"; -import DeclarationFields from "./fields/DeclarationFields"; -import EnhetFields from "./fields/EnhetFields"; -import SignatureFields from "./fields/SignatureFields"; -import SubmissionFields from "./fields/SubmissionFields"; -import LabelWithDiff from "./LabelWithDiff"; -import { FormMetadataError, UpdateFormFunction } from "./utils"; +import { Alert, Fieldset, Textarea, TextField } from '@navikt/ds-react'; +import { formDiffingTool, NavFormType, TEXTS, UsageContext } from '@navikt/skjemadigitalisering-shared-domain'; +import AddressFields from './fields/AddressFields'; +import BasicFields from './fields/BasicFields'; +import DeclarationFields from './fields/DeclarationFields'; +import EnhetFields from './fields/EnhetFields'; +import SignatureFields from './fields/SignatureFields'; +import SubmissionFields from './fields/SubmissionFields'; +import LabelWithDiff from './LabelWithDiff'; +import { FormMetadataError, UpdateFormFunction } from './utils'; interface Props { form: NavFormType; @@ -38,7 +38,7 @@ const BasicFormMetadataEditor = ({ form, publishedForm, onChange, usageContext, label={} type="text" id="downloadPdfButtonText" - value={downloadPdfButtonText || ""} + value={downloadPdfButtonText || ''} onChange={(event) => onChange({ ...form, @@ -61,7 +61,7 @@ const BasicFormMetadataEditor = ({ form, publishedForm, onChange, usageContext, <>