From 3efd25f13bde413bbc2fa280d0bd00bdeff991ff Mon Sep 17 00:00:00 2001 From: Tobias Kampmann Date: Thu, 22 Feb 2024 19:14:33 +0100 Subject: [PATCH] feat(website): address comments feat(website): remove hardcoded accessions from e2e --- website/.nvmrc | 2 +- website/tests/e2e.fixture.ts | 25 +-- website/tests/pages/search/index.spec.ts | 22 ++- .../pages/sequences/accession.fa.spec.ts | 18 +- .../tests/pages/sequences/accession.spec.ts | 39 ++-- .../tests/pages/sequences/sequences.page.ts | 9 +- website/tests/pages/submit/submit.page.ts | 2 - website/tests/playwrightSetup.ts | 186 ++++++++---------- website/tests/util/accessionTransformer.ts | 79 -------- website/tests/util/preprocessingPipeline.ts | 6 +- website/tests/util/testSequenceProvider.ts | 20 ++ 11 files changed, 157 insertions(+), 251 deletions(-) delete mode 100644 website/tests/util/accessionTransformer.ts create mode 100644 website/tests/util/testSequenceProvider.ts diff --git a/website/.nvmrc b/website/.nvmrc index 85aee5a53..216dbec85 100644 --- a/website/.nvmrc +++ b/website/.nvmrc @@ -1 +1 @@ -v20 \ No newline at end of file +v21 \ No newline at end of file diff --git a/website/tests/e2e.fixture.ts b/website/tests/e2e.fixture.ts index ac8b1db9f..4347f6469 100644 --- a/website/tests/e2e.fixture.ts +++ b/website/tests/e2e.fixture.ts @@ -16,7 +16,6 @@ import { SequencePage } from './pages/sequences/sequences.page'; import { SubmitPage } from './pages/submit/submit.page'; import { GroupPage } from './pages/user/group/group.page.ts'; import { UserSequencePage } from './pages/user/userSequencePage/userSequencePage.ts'; -import { AccessionTransformer } from './util/accessionTransformer.ts'; import { createGroup } from './util/backendCalls.ts'; import { ACCESS_TOKEN_COOKIE, clientMetadata, realmPath, REFRESH_TOKEN_COOKIE } from '../src/middleware/authMiddleware'; import { BackendClient } from '../src/services/backendClient'; @@ -56,35 +55,13 @@ export const e2eLogger = winston.createLogger({ transports: [new winston.transports.Console()], }); -export const accessionPrefix = 'LOC_'; -export const accessionTransformer = new AccessionTransformer(accessionPrefix); - export const backendClient = BackendClient.create(backendUrl, e2eLogger); export const groupManagementClient = GroupManagementClient.create(backendUrl, e2eLogger); -export const testSequenceEntry = { - name: `${accessionTransformer.generateCustomId(1)}.1`, - accession: accessionTransformer.generateCustomId(1), - version: 1, +export const testSequenceEntryData = { unaligned: 'A'.repeat(123), orf1a: 'QRFEINSA', }; -export const revokedSequenceEntry = { - accession: accessionTransformer.generateCustomId(11), - version: 1, -}; -export const revocationSequenceEntry = { - accession: accessionTransformer.generateCustomId(11), - version: 2, -}; -export const deprecatedSequenceEntry = { - accession: accessionTransformer.generateCustomId(21), - version: 1, -}; -export const revisedSequenceEntry = { - accession: accessionTransformer.generateCustomId(21), - version: 2, -}; export const testUser = 'testuser'; export const testUserPassword = 'testuser'; diff --git a/website/tests/pages/search/index.spec.ts b/website/tests/pages/search/index.spec.ts index 40de63411..020c7975f 100644 --- a/website/tests/pages/search/index.spec.ts +++ b/website/tests/pages/search/index.spec.ts @@ -1,7 +1,9 @@ import { DateTime } from 'luxon'; import { routes } from '../../../src/routes.ts'; -import { baseUrl, dummyOrganism, expect, test, testSequenceEntry } from '../../e2e.fixture'; +import { baseUrl, dummyOrganism, expect, test } from '../../e2e.fixture'; +import { getAccessionVersionString } from '../../../src/utils/extractAccessionVersion.ts'; +import { getTestSequences } from '../../util/testSequenceProvider.ts'; test.describe('The search page', () => { test('should show the search form with button and a table', async ({ searchPage }) => { @@ -20,16 +22,22 @@ test.describe('The search page', () => { }); test('should search for existing sequence entries', async ({ searchPage }) => { + const testAccessionVersion = getAccessionVersionString(getTestSequences().testSequenceEntry); + await searchPage.goto(); - await searchPage.getEmptyAccessionVersionField().fill(testSequenceEntry.name); + await searchPage.getEmptyAccessionVersionField().fill(testAccessionVersion); await searchPage.clickSearchButton(); await searchPage.page.waitForURL( `${baseUrl}${routes.searchPage(dummyOrganism.key, [ - { name: 'accessionVersion', type: 'string', filterValue: testSequenceEntry.name }, + { + name: 'accessionVersion', + type: 'string', + filterValue: testAccessionVersion, + }, ])}`, ); - await expect(searchPage.page.getByText(testSequenceEntry.name, { exact: true })).toBeVisible(); + await expect(searchPage.page.getByText(testAccessionVersion, { exact: true })).toBeVisible(); await expect(searchPage.page.getByText('2002-12-15')).toBeVisible(); await expect(searchPage.page.getByText('B.1.1.7')).toBeVisible(); }); @@ -45,9 +53,11 @@ test.describe('The search page', () => { test('should reset the search', async ({ searchPage }) => { await searchPage.goto(); - await searchPage.getEmptyAccessionVersionField().fill(testSequenceEntry.name); - await expect(searchPage.getFilledAccessionVersionField()).toHaveValue(testSequenceEntry.name); + const testAccessionVersion = getAccessionVersionString(getTestSequences().testSequenceEntry); + await searchPage.getEmptyAccessionVersionField().fill(testAccessionVersion); + + await expect(searchPage.getFilledAccessionVersionField()).toHaveValue(testAccessionVersion); await searchPage.clickResetButton(); diff --git a/website/tests/pages/sequences/accession.fa.spec.ts b/website/tests/pages/sequences/accession.fa.spec.ts index 9f35f49c0..9b3514412 100644 --- a/website/tests/pages/sequences/accession.fa.spec.ts +++ b/website/tests/pages/sequences/accession.fa.spec.ts @@ -1,21 +1,29 @@ import { routes } from '../../../src/routes.ts'; -import { baseUrl, dummyOrganism, expect, test, testSequenceEntry } from '../../e2e.fixture'; +import { baseUrl, dummyOrganism, expect, test, testSequenceEntryData } from '../../e2e.fixture'; +import { getAccessionVersionString } from '../../../src/utils/extractAccessionVersion.ts'; +import { getTestSequences } from '../../util/testSequenceProvider.ts'; test.describe('The sequence.fa page', () => { test('can load and show fasta file', async () => { - const url = `${baseUrl}${routes.sequencesFastaPage(dummyOrganism.key, testSequenceEntry)}`; + const testSequences = getTestSequences(); + + const url = `${baseUrl}${routes.sequencesFastaPage(dummyOrganism.key, testSequences.testSequenceEntry)}`; const response = await fetch(url); const content = await response.text(); - expect(content).toBe(`>${testSequenceEntry.name}\n${testSequenceEntry.unaligned}\n`); + expect(content).toBe( + `>${getAccessionVersionString(testSequences.testSequenceEntry)}\n${testSequenceEntryData.unaligned}\n`, + ); }); test('can download fasta file', async () => { - const downloadUrl = `${baseUrl}${routes.sequencesFastaPage(dummyOrganism.key, testSequenceEntry, true)}`; + const testSequences = getTestSequences(); + + const downloadUrl = `${baseUrl}${routes.sequencesFastaPage(dummyOrganism.key, testSequences.testSequenceEntry, true)}`; const response = await fetch(downloadUrl); const contentDisposition = response.headers.get('Content-Disposition'); expect(contentDisposition).not.toBeNull(); expect(contentDisposition).toContain('attachment'); - expect(contentDisposition).toContain(testSequenceEntry.name); + expect(contentDisposition).toContain(getAccessionVersionString(testSequences.testSequenceEntry)); }); }); diff --git a/website/tests/pages/sequences/accession.spec.ts b/website/tests/pages/sequences/accession.spec.ts index 42e0d5ab4..1b8b1381d 100644 --- a/website/tests/pages/sequences/accession.spec.ts +++ b/website/tests/pages/sequences/accession.spec.ts @@ -1,55 +1,52 @@ import { routes } from '../../../src/routes.ts'; import { getAccessionVersionString } from '../../../src/utils/extractAccessionVersion.ts'; -import { - baseUrl, - deprecatedSequenceEntry, - dummyOrganism, - expect, - revisedSequenceEntry, - revocationSequenceEntry, - revokedSequenceEntry, - test, - testSequenceEntry, -} from '../../e2e.fixture'; +import { baseUrl, dummyOrganism, expect, test, testSequenceEntryData } from '../../e2e.fixture'; +import { getTestSequences } from '../../util/testSequenceProvider.ts'; test.describe('The detailed sequence page', () => { test('can load and show sequence data', async ({ sequencePage }) => { - await sequencePage.goto(); - await expect(sequencePage.page.getByText(testSequenceEntry.orf1a)).not.toBeVisible(); + const testSequenceEntry = getTestSequences().testSequenceEntry; + + await sequencePage.goto(testSequenceEntry); + await expect(sequencePage.page.getByText(testSequenceEntryData.orf1a)).not.toBeVisible(); await sequencePage.loadSequences(); await sequencePage.clickORF1aButton(); - await expect(sequencePage.page.getByText(testSequenceEntry.orf1a, { exact: false })).toBeVisible(); + await expect(sequencePage.page.getByText(testSequenceEntryData.orf1a, { exact: false })).toBeVisible(); }); test('check initial sequences and verify that banners are shown when revoked or revised', async ({ sequencePage, }) => { - await sequencePage.goto(revokedSequenceEntry); + const testSequences = getTestSequences(); + + await sequencePage.goto(testSequences.revokedSequenceEntry); await expect(sequencePage.page.getByText(`This sequence entry has been revoked!`)).toBeVisible(); await expect(sequencePage.notLatestVersionBanner).toBeVisible(); - await sequencePage.goto(revocationSequenceEntry); + await sequencePage.goto(testSequences.revocationSequenceEntry); await expect(sequencePage.revocationVersionBanner).toBeVisible(); - await sequencePage.goto(deprecatedSequenceEntry); + await sequencePage.goto(testSequences.deprecatedSequenceEntry); await expect(sequencePage.notLatestVersionBanner).toBeVisible(); - await sequencePage.goto(revisedSequenceEntry); + await sequencePage.goto(testSequences.revisedSequenceEntry); await expect(sequencePage.notLatestVersionBanner).not.toBeVisible(); }); test('can navigate to the versions page and click the link to the deprecated version', async ({ sequencePage }) => { - await sequencePage.goto(revisedSequenceEntry); + const testSequences = getTestSequences(); + + await sequencePage.goto(testSequences.revisedSequenceEntry); await sequencePage.gotoAllVersions(); await expect( - sequencePage.page.getByText(`Versions for accession ${revisedSequenceEntry.accession}`), + sequencePage.page.getByText(`Versions for accession ${testSequences.revisedSequenceEntry.accession}`), ).toBeVisible(); await expect(sequencePage.page.getByText(`Latest version`)).toBeVisible(); await expect(sequencePage.page.getByText(`Revised`)).toBeVisible(); - const deprecatedVersionString = getAccessionVersionString(deprecatedSequenceEntry); + const deprecatedVersionString = getAccessionVersionString(testSequences.deprecatedSequenceEntry); const linkToDeprecatedVersion = sequencePage.page.getByRole('link', { name: `${deprecatedVersionString}`, }); diff --git a/website/tests/pages/sequences/sequences.page.ts b/website/tests/pages/sequences/sequences.page.ts index a23aac69b..bfe95a594 100644 --- a/website/tests/pages/sequences/sequences.page.ts +++ b/website/tests/pages/sequences/sequences.page.ts @@ -3,14 +3,15 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { routes } from '../../../src/routes.ts'; import type { AccessionVersion } from '../../../src/types/backend.ts'; import { getAccessionVersionString } from '../../../src/utils/extractAccessionVersion.ts'; -import { baseUrl, dummyOrganism, testSequenceEntry } from '../../e2e.fixture'; +import { baseUrl, dummyOrganism } from '../../e2e.fixture'; export class SequencePage { + public readonly notLatestVersionBanner: Locator; + public readonly revocationVersionBanner: Locator; + private readonly loadButton: Locator; private readonly allVersions: Locator; private readonly orf1aButton: Locator; - readonly notLatestVersionBanner: Locator; - readonly revocationVersionBanner: Locator; constructor(public readonly page: Page) { this.loadButton = this.page.getByRole('button', { name: 'Load sequences' }); @@ -22,7 +23,7 @@ export class SequencePage { this.revocationVersionBanner = this.page.getByText('This is a revocation version.'); } - public async goto(accessionVersion: AccessionVersion = testSequenceEntry) { + public async goto(accessionVersion: AccessionVersion) { await this.page.goto(`${baseUrl}${routes.sequencesDetailsPage(dummyOrganism.key, accessionVersion)}`, { waitUntil: 'networkidle', }); diff --git a/website/tests/pages/submit/submit.page.ts b/website/tests/pages/submit/submit.page.ts index 174ce83b0..34893f8d4 100644 --- a/website/tests/pages/submit/submit.page.ts +++ b/website/tests/pages/submit/submit.page.ts @@ -1,7 +1,6 @@ import type { Locator, Page } from '@playwright/test'; import { routes } from '../../../src/routes.ts'; -import { restrictedDataUseTermsType } from '../../../src/types/backend.ts'; import { baseUrl, compressedMetadataTestFile, @@ -10,7 +9,6 @@ import { metadataTestFile, sequencesTestFile, } from '../../e2e.fixture'; -import { expect } from '../../e2e.fixture.ts'; export class SubmitPage { public readonly submitButton: Locator; diff --git a/website/tests/playwrightSetup.ts b/website/tests/playwrightSetup.ts index 9005961ac..3da052721 100644 --- a/website/tests/playwrightSetup.ts +++ b/website/tests/playwrightSetup.ts @@ -1,8 +1,4 @@ -import isEqual from 'lodash/isEqual.js'; -import sortBy from 'lodash/sortBy.js'; - import { - accessionPrefix, createTestGroupIfNotExistent, DEFAULT_GROUP_NAME, e2eLogger, @@ -11,14 +7,13 @@ import { testUser, testUserPassword, } from './e2e.fixture.ts'; -import { AccessionTransformer } from './util/accessionTransformer.ts'; import { prepareDataToBe } from './util/prepareDataToBe.ts'; import { LapisClient } from '../src/services/lapisClient.ts'; -import { ACCESSION_FIELD, IS_REVOCATION_FIELD, VERSION_FIELD, VERSION_STATUS_FIELD } from '../src/settings.ts'; -import { siloVersionStatuses } from '../src/types/lapis.ts'; +import type { AccessionVersion } from '../src/types/backend.ts'; +import { getTestSequences, setTestSequences } from './util/testSequenceProvider.ts'; enum LapisStateBeforeTests { - NoSequencesInLapis = 'NoSequencesInLapis', + NotCorrectSequencesInLapis = 'NotCorrectSequencesInLapis', CorrectSequencesInLapis = 'CorrectSequencesInLapis', } @@ -51,10 +46,8 @@ export default async function globalSetupForPlaywright() { const lapisState = await checkLapisState(lapisClient); if (lapisState === LapisStateBeforeTests.CorrectSequencesInLapis) { - e2eLogger.info( - 'Skipping data preparation. ' + - 'NOTE: data preparation has to be done before on an empty LAPIS. Expected data found.', - ); + const testSequences = getTestSequences(); + e2eLogger.info('Skipping data preparation. Expected data found. ' + JSON.stringify(testSequences)); return; } @@ -94,113 +87,94 @@ function waitSeconds(seconds: number) { } async function checkLapisState(lapisClient: LapisClient): Promise { - const accessionTransformer = new AccessionTransformer(accessionPrefix); - const numberOfSequencesInLapisResult = await lapisClient.call('aggregated', {}); if (numberOfSequencesInLapisResult.isErr() && numberOfSequencesInLapisResult.error.status === 503) { - return LapisStateBeforeTests.NoSequencesInLapis; + return LapisStateBeforeTests.NotCorrectSequencesInLapis; } if (numberOfSequencesInLapisResult._unsafeUnwrap().data[0].count === 0) { - return LapisStateBeforeTests.NoSequencesInLapis; + return LapisStateBeforeTests.NotCorrectSequencesInLapis; } - const [singleLatestVersionAccession, revisedAndRevokedAccession, revisedAccession] = - accessionTransformer.generateCustomIds([1, 11, 21]); - - e2eLogger.info( - 'Checking LAPIS for sequences with accessions: ' + - singleLatestVersionAccession + - ', ' + - revisedAndRevokedAccession + - ', ' + - revisedAccession, - ); + const latestVersionWithoutRevisions = await getLatestVersionWithoutRevisions(lapisClient); - const fields = [ACCESSION_FIELD, VERSION_FIELD, VERSION_STATUS_FIELD, IS_REVOCATION_FIELD]; - const [ - shouldBeLatestVersionResult, - // When SILO can process revocation_entries, we expect two versions. - shouldBeTwoVersionsAndOneRevokedResult, - shouldBeTwoVersionsAndOneRevisedResult, - ] = await Promise.all([ - lapisClient.call('details', { accession: singleLatestVersionAccession, fields }), - lapisClient.call('details', { accession: revisedAndRevokedAccession, fields }), - lapisClient.call('details', { accession: revisedAccession, fields }), - ]); - - const shouldBeLatestVersionAndNotRevoked = sortBy(shouldBeLatestVersionResult._unsafeUnwrap().data, [ - VERSION_FIELD, - ]); - const shouldBeTwoVersionsAndOneRevoked = sortBy(shouldBeTwoVersionsAndOneRevokedResult._unsafeUnwrap().data, [ - VERSION_FIELD, - ]); - const shouldBeTwoVersionsAndOneRevised = sortBy(shouldBeTwoVersionsAndOneRevisedResult._unsafeUnwrap().data, [ - VERSION_FIELD, - ]); - - const expectedLatestVersions = [ - { - accession: singleLatestVersionAccession, - version: 1, - versionStatus: siloVersionStatuses.latestVersion, - isRevocation: 'false', - }, - ]; - - if (!isEqual(shouldBeLatestVersionAndNotRevoked, expectedLatestVersions)) { - throw new Error( - `Unexpected data in LAPIS. Please check the data preparation. Received: ${JSON.stringify( - shouldBeLatestVersionAndNotRevoked, - )} Expected: ${JSON.stringify(expectedLatestVersions)}`, - ); + if (latestVersionWithoutRevisions === undefined) { + e2eLogger.error('latestVersionWithoutRevisions is undefined'); + return LapisStateBeforeTests.NotCorrectSequencesInLapis; } - const expectedRevokedVersions = [ - { - accession: revisedAndRevokedAccession, - version: 1, - versionStatus: siloVersionStatuses.revoked, - isRevocation: 'false', - }, - { - accession: revisedAndRevokedAccession, - version: 2, - versionStatus: siloVersionStatuses.latestVersion, - isRevocation: 'true', - }, - ]; - - if (!isEqual(shouldBeTwoVersionsAndOneRevoked, expectedRevokedVersions)) { - throw new Error( - `Unexpected data in LAPIS. Please check the data preparation. Received: ${JSON.stringify( - shouldBeTwoVersionsAndOneRevoked, - )} Expected: ${JSON.stringify(expectedRevokedVersions)}`, - ); + const testSequenceEntry = { + accession: `${latestVersionWithoutRevisions.accession}`, + version: 1, + }; + + const revocationEntryAsLatestVersion = await getRevocationEntryAsLatestVersion(lapisClient); + + if (revocationEntryAsLatestVersion === undefined) { + e2eLogger.error('revocationEntryAsLatestVersion is undefined'); + return LapisStateBeforeTests.NotCorrectSequencesInLapis; } - const expectedRevisedVersions = [ - { - accession: revisedAccession, - version: 1, - versionStatus: siloVersionStatuses.revised, - isRevocation: 'false', - }, - { - accession: revisedAccession, - version: 2, - versionStatus: siloVersionStatuses.latestVersion, - isRevocation: 'false', - }, - ]; - - if (!isEqual(sortBy(shouldBeTwoVersionsAndOneRevised, ['version']), expectedRevisedVersions)) { - throw new Error( - `Unexpected data in LAPIS. Please check the data preparation. Received: ${JSON.stringify( - shouldBeTwoVersionsAndOneRevised, - )} Expected: ${JSON.stringify(expectedRevisedVersions)}`, - ); + const revocationSequenceEntry = revocationEntryAsLatestVersion; + const revokedSequenceEntry = { + accession: `${revocationEntryAsLatestVersion.accession}`, + version: 1, + }; + + const revisedEntryAsLatestVersionWhichIsSecondVersion = await getRevisedEntryAsLatestVersion(lapisClient); + + if (revisedEntryAsLatestVersionWhichIsSecondVersion === undefined) { + e2eLogger.error('revisedEntryAsLatestVersionWhichIsVersion2 is undefined'); + return LapisStateBeforeTests.NotCorrectSequencesInLapis; } + + const revisedSequenceEntry = revisedEntryAsLatestVersionWhichIsSecondVersion; + const deprecatedSequenceEntry = { + accession: `${revisedEntryAsLatestVersionWhichIsSecondVersion.accession}`, + version: 1, + }; + + setTestSequences({ + testSequenceEntry, + revokedSequenceEntry, + revocationSequenceEntry, + deprecatedSequenceEntry, + revisedSequenceEntry, + }); + return LapisStateBeforeTests.CorrectSequencesInLapis; } + +async function getLatestVersionWithoutRevisions(lapisClient: LapisClient) { + const result = await lapisClient.call('details', { + versionTo: 1, + isRevocation: 'false', + limit: 1, + versionStatus: 'LATEST_VERSION', + fields: ['accession', 'version'], + }); + return result._unsafeUnwrap().data[0] as AccessionVersion | undefined; +} + +async function getRevocationEntryAsLatestVersion(lapisClient: LapisClient) { + const result = await lapisClient.call('details', { + isRevocation: 'true', + version: 2, + limit: 1, + versionStatus: 'LATEST_VERSION', + fields: ['accession', 'version'], + }); + return result._unsafeUnwrap().data[0] as AccessionVersion | undefined; +} + +async function getRevisedEntryAsLatestVersion(lapisClient: LapisClient) { + const result = await lapisClient.call('details', { + isRevocation: 'false', + version: 2, + limit: 1, + versionStatus: 'LATEST_VERSION', + fields: ['accession', 'version'], + }); + return result._unsafeUnwrap().data[0] as AccessionVersion | undefined; +} diff --git a/website/tests/util/accessionTransformer.ts b/website/tests/util/accessionTransformer.ts deleted file mode 100644 index 68f4d2420..000000000 --- a/website/tests/util/accessionTransformer.ts +++ /dev/null @@ -1,79 +0,0 @@ -export class AccessionTransformer { - private static readonly CODE_POINTS: string = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ'; - private readonly accessionPrefix: string; - - constructor(accessionPrefix: string) { - this.accessionPrefix = accessionPrefix; - } - - public generateCustomIds(sequenceNumbers: number[]): string[] { - return sequenceNumbers.map(this.generateCustomId.bind(this)); - } - - public generateCustomId(sequenceNumber: number): string { - const base34Digits: string[] = []; - let remainder: number = sequenceNumber; - - do { - const digit: number = remainder % 34; - base34Digits.push(AccessionTransformer.CODE_POINTS[digit]); - remainder = Math.floor(remainder / 34); - } while (remainder > 0); - - while (base34Digits.length < 6) { - base34Digits.push('0'); - } - - const serialAccessionPart: string = base34Digits.reverse().join(''); - return this.accessionPrefix + serialAccessionPart + this.generateCheckCharacter(serialAccessionPart); - } - - public validateAccession(accession: string): boolean { - if (!accession.startsWith(this.accessionPrefix)) { - return false; - } - return this.validateCheckCharacter(accession.substring(this.accessionPrefix.length)); - } - - private generateCheckCharacter(input: string): string { - let factor: number = 2; - let sum: number = 0; - const numberOfValidInputCharacters: number = AccessionTransformer.CODE_POINTS.length; - - for (let i: number = input.length - 1; i >= 0; i--) { - let addend: number = factor * this.getCodePointFromCharacter(input[i]); - - factor = factor === 2 ? 1 : 2; - - addend = Math.floor(addend / numberOfValidInputCharacters) + (addend % numberOfValidInputCharacters); - sum += addend; - } - - const remainder: number = sum % numberOfValidInputCharacters; - const checkCodePoint: number = (numberOfValidInputCharacters - remainder) % numberOfValidInputCharacters; - return AccessionTransformer.CODE_POINTS.charAt(checkCodePoint); - } - - private validateCheckCharacter(input: string): boolean { - let factor: number = 1; - let sum: number = 0; - const numberOfValidInputCharacters: number = AccessionTransformer.CODE_POINTS.length; - - for (let i: number = input.length - 1; i >= 0; i--) { - const codePoint: number = this.getCodePointFromCharacter(input[i]); - let addend: number = factor * codePoint; - - factor = factor === 2 ? 1 : 2; - - addend = Math.floor(addend / numberOfValidInputCharacters) + (addend % numberOfValidInputCharacters); - sum += addend; - } - - const remainder: number = sum % numberOfValidInputCharacters; - return remainder === 0; - } - - private getCodePointFromCharacter(character: string): number { - return AccessionTransformer.CODE_POINTS.indexOf(character); - } -} diff --git a/website/tests/util/preprocessingPipeline.ts b/website/tests/util/preprocessingPipeline.ts index 1a3a86df4..b0b998c67 100644 --- a/website/tests/util/preprocessingPipeline.ts +++ b/website/tests/util/preprocessingPipeline.ts @@ -3,7 +3,7 @@ import type { AxiosError } from 'axios'; import { BackendClient } from '../../src/services/backendClient.ts'; import { type Accession, unprocessedData, type UnprocessedData } from '../../src/types/backend.ts'; import { stringifyMaybeAxiosError } from '../../src/utils/stringifyMaybeAxiosError.ts'; -import { backendUrl, dummyOrganism, e2eLogger, getToken, testSequenceEntry } from '../e2e.fixture.ts'; +import { backendUrl, dummyOrganism, e2eLogger, getToken, testSequenceEntryData } from '../e2e.fixture.ts'; export const fakeProcessingPipeline = { submit, @@ -103,7 +103,7 @@ const handleError = (error: unknown): Error => { const sequenceData = { unalignedNucleotideSequences: { - main: testSequenceEntry.unaligned, + main: testSequenceEntryData.unaligned, }, alignedNucleotideSequences: { main: 'N' + 'A'.repeat(29902), @@ -115,7 +115,7 @@ const sequenceData = { E: 'M'.repeat(76), M: 'A'.repeat(223), N: 'S'.repeat(420), - ORF1a: testSequenceEntry.orf1a + 'E'.repeat(4401 - testSequenceEntry.orf1a.length), + ORF1a: testSequenceEntryData.orf1a + 'E'.repeat(4401 - testSequenceEntryData.orf1a.length), ORF1b: 'R'.repeat(2696), ORF3a: 'D'.repeat(276), ORF6: 'F'.repeat(62), diff --git a/website/tests/util/testSequenceProvider.ts b/website/tests/util/testSequenceProvider.ts new file mode 100644 index 000000000..04ba7dfa9 --- /dev/null +++ b/website/tests/util/testSequenceProvider.ts @@ -0,0 +1,20 @@ +import type { AccessionVersion } from '../../src/types/backend.ts'; + +export type TestSequenceContainer = { + testSequenceEntry: AccessionVersion; + revokedSequenceEntry: AccessionVersion; + revocationSequenceEntry: AccessionVersion; + deprecatedSequenceEntry: AccessionVersion; + revisedSequenceEntry: AccessionVersion; +}; + +export const getTestSequences = (): TestSequenceContainer => { + if (process.env.TEST_SEQUENCES === undefined) { + throw new Error('TEST_SEQUENCES is not set. Preparation failed.'); + } + return JSON.parse(process.env.TEST_SEQUENCES); +}; + +export const setTestSequences = (testSequences: TestSequenceContainer) => { + process.env.TEST_SEQUENCES = JSON.stringify(testSequences); +};