From 1a0b20e33c04b7d7729439a77d4528a159dc26a0 Mon Sep 17 00:00:00 2001 From: Aref Shafaei Date: Thu, 13 Jun 2024 12:05:18 -0700 Subject: [PATCH] Add test cases for static navbar and migrate links spec (#2481) * add test cases for static navbar + migrate links spec --- Makefile | 6 +- docs/dev-docs/e2e-test-writing.md | 5 + package-lock.json | 8 +- package.json | 2 +- test/e2e/data_setup/schema/record/links.json | 2 +- test/e2e/setup/playwright.model.ts | 11 +- test/e2e/setup/playwright.setup.ts | 16 +- .../chaise-config.js | 4 - .../errors/errors.config.ts | 2 +- .../footer/playwright.config.ts | 2 +- .../navbar/playwright.config.ts | 2 +- .../playwright.config.ts | 2 +- .../all-features/navbar/playwright.config.ts | 2 +- .../specs/all-features/permissions.config.ts | 2 +- .../specs/all-features/playwright.config.ts | 2 +- .../all-features/record/copy-btn.config.ts | 2 +- .../record/related-table.config.ts | 2 +- .../recordedit/input-iframe.config.ts | 2 +- .../recordedit/input-iframe.spec.ts | 22 +- .../recordset/saved-query.config.ts | 4 +- .../e2e/specs/default-config/chaise-config.js | 4 - .../multi-form-input.config.ts | 2 +- .../specs/default-config/playwright.config.ts | 2 +- .../specs/default-config/record/links.conf.js | 15 -- .../default-config/record/links.config.ts | 10 + .../specs/default-config/record/links.spec.js | 250 ------------------ .../specs/default-config/record/links.spec.ts | 152 +++++++++++ .../recordedit/composite-key.config.ts | 2 +- .../recordedit/domain-filter.config.ts | 2 +- .../recordedit/foreign-key-dropdown.config.ts | 2 +- .../specs/delete-prohibited/chaise-config.js | 5 +- .../navbar/catalog-chaise-config.spec.ts | 237 ++++++++++++++--- .../navbar/playwright.config.ts | 2 +- .../delete-prohibited/playwright.config.ts | 2 +- .../record/no-delete-btn.config.ts | 2 +- .../recordset/histogram-facet.config.ts | 6 +- .../recordset/ind-facet.config.ts | 6 +- test/e2e/utils/catalog-utils.ts | 38 ++- test/e2e/utils/navbar-test.html | 12 + test/e2e/utils/page-utils.ts | 9 +- test/e2e/utils/protractor.import.js | 21 +- 41 files changed, 503 insertions(+), 378 deletions(-) delete mode 100644 test/e2e/specs/default-config/record/links.conf.js create mode 100644 test/e2e/specs/default-config/record/links.config.ts delete mode 100644 test/e2e/specs/default-config/record/links.spec.js create mode 100644 test/e2e/specs/default-config/record/links.spec.ts create mode 100644 test/e2e/utils/navbar-test.html diff --git a/Makefile b/Makefile index c193df05f..51ce5743c 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ E2EDrecord=test/e2e/specs/all-features-confirmation/record/presentation-btn.conf E2EDrecordCopy=test/e2e/specs/all-features/record/copy-btn.config.ts E2ErecordNoDeleteBtn=test/e2e/specs/delete-prohibited/record/no-delete-btn.config.ts E2EDrecordRelatedTable=test/e2e/specs/all-features/record/related-table.config.ts -E2EDrecordLinks=test/e2e/specs/default-config/record/links.conf.js +E2EDrecordLinks=test/e2e/specs/default-config/record/links.config.ts # Recordset tests E2EDrecordset=test/e2e/specs/all-features-confirmation/recordset/presentation.conf.js E2EDrecordsetEdit=test/e2e/specs/default-config/recordset/edit.conf.js @@ -93,7 +93,7 @@ DefaultConfigParallel=test/e2e/specs/default-config/playwright.config.ts Manualrecordset=test/manual/specs/recordset.conf.js # protractor tests -RECORD_TESTS_PROTRACTOR=$(E2EDrecord) $(E2EDrecordLinks) +RECORD_TESTS_PROTRACTOR=$(E2EDrecord) RECORDSET_TESTS_PROTRACTOR=$(E2EDrecordset) $(E2ErecordsetAdd) $(E2EDrecordsetEdit) $(E2EDrecordsetIndFacetProt) RECORDADD_TESTS_PROTRACTOR=$(E2EDIrecordAdd) $(E2EDIrecordMultiFormInput) $(E2EDIrecordImmutable) RECORDEDIT_TESTS_PROTRACTOR=$(E2EDIrecordEdit) $(E2EDIrecordMultiEdit) $(E2EDrecordEditSubmissionDisabled) $(E2EDIrecordEditMultiColTypes) @@ -105,7 +105,7 @@ ALL_TESTS_PROTRACTOR=$(RECORD_TESTS_PROTRACTOR) $(RECORDSET_TESTS_PROTRACTOR) $( # playwright tests NAVBAR_TESTS=$(E2Enavbar) $(E2EnavbarHeadTitle) $(E2EnavbarCatalogConfig) -RECORD_TESTS=$(E2ErecordNoDeleteBtn) $(E2EDrecordRelatedTable) $(E2EDrecordCopy) +RECORD_TESTS=$(E2ErecordNoDeleteBtn) $(E2EDrecordRelatedTable) $(E2EDrecordCopy) $(E2EDrecordLinks) RECORDSET_TESTS=$(E2ErecordsetSavedQuery) $(E2EDrecordsetIndFacet) $(E2EDrecordsetHistFacet) RECORDADD_TESTS=$(E2EDIrecordMultiFormInput) $(E2ErecordEditForeignKeyDropdown) $(E2EDrecordEditCompositeKey) RECORDEDIT_TESTS=$(E2ErecordEditInputIframe) $(E2EDrecordEditDomainFilter) diff --git a/docs/dev-docs/e2e-test-writing.md b/docs/dev-docs/e2e-test-writing.md index 493d3c47b..69a57a665 100644 --- a/docs/dev-docs/e2e-test-writing.md +++ b/docs/dev-docs/e2e-test-writing.md @@ -60,6 +60,11 @@ This section summarizes the best practices for writing test cases in Chaise. }); }); ``` + - If your file has multiple independent `test`s that can run in parallel, you can ask playwright to run them in parallel by adding the following: + ```ts + test.describe.configure({ mode: 'parallel' }); + ``` + - Don't use this configuration if you have a `beforeAll` or `afterAll` that you want to run only once. Because in this case each worker will run their own `beforeAll` and `afterAll` instead of running it once (https://github.com/microsoft/playwright/issues/28201). - If your tests must run in order and on the same browser, use the `test.step` method. - Don't forget to include `await` before each `test.step`. - Playwright will not run the remaining steps if any of the steps fail. To get around this, you should use `expect.soft`. diff --git a/package-lock.json b/package-lock.json index 21ade8485..7ea2a5cce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,8 +47,8 @@ "webpack-cli": "^4.9.2" }, "devDependencies": { - "@isrd-isi-edu/ermrest-data-utils": "0.0.5", - "@playwright/test": "*", + "@isrd-isi-edu/ermrest-data-utils": "^0.0.6", + "@playwright/test": "latest", "@typescript-eslint/eslint-plugin": "~7.1.0", "@typescript-eslint/parser": "~7.1.0", "chance": "x", @@ -1995,7 +1995,9 @@ "dev": true }, "node_modules/@isrd-isi-edu/ermrest-data-utils": { - "version": "0.0.5", + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@isrd-isi-edu/ermrest-data-utils/-/ermrest-data-utils-0.0.6.tgz", + "integrity": "sha512-bcomhFkX814wBSd/jjHEoTaXFlT5Wtzwz1fc+YjD6tp0mJHtNHYz1CMqFb8uG54udjWo0fJ9xAXrVfA7PxCj3Q==", "dev": true, "dependencies": { "axios": "^1.6.0", diff --git a/package.json b/package.json index 38c1790a2..cdecbe561 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "ui" ], "devDependencies": { - "@isrd-isi-edu/ermrest-data-utils": "0.0.5", + "@isrd-isi-edu/ermrest-data-utils": "^0.0.6", "@playwright/test": "latest", "@typescript-eslint/eslint-plugin": "~7.1.0", "@typescript-eslint/parser": "~7.1.0", diff --git a/test/e2e/data_setup/schema/record/links.json b/test/e2e/data_setup/schema/record/links.json index bfe5585a4..2938aee69 100644 --- a/test/e2e/data_setup/schema/record/links.json +++ b/test/e2e/data_setup/schema/record/links.json @@ -162,7 +162,7 @@ "annotations": { "tag:isrd.isi.edu,2016:visible-columns" : { "detailed": [ - "id", "text", "int", ["links", "fk_assoc_links"] + "id", "text", "int", ["links", "fk_inline_assoc_inline"] ] } } diff --git a/test/e2e/setup/playwright.model.ts b/test/e2e/setup/playwright.model.ts index 212367304..30cfbe583 100644 --- a/test/e2e/setup/playwright.model.ts +++ b/test/e2e/setup/playwright.model.ts @@ -1,4 +1,11 @@ export type TestOptions = { + /** + * the name of the main spec folder. + * usages: + * - the catalog alias + * - finding the folder (for default chaise-config.js) + */ + mainSpecName: string, /** * the name of the spec (will be used for the report file) */ @@ -11,8 +18,10 @@ export type TestOptions = { configFileName: string, /** * location of the chaise config file + * (if misisng, we're using mainSpecName to find the chaise-config file). + * /test/e2e/specs//chaise-config.js */ - chaiseConfigFilePath: string, + chaiseConfigFilePath?: string, manualTestConfig?: boolean, diff --git a/test/e2e/setup/playwright.setup.ts b/test/e2e/setup/playwright.setup.ts index aca9bf6ef..176042c83 100644 --- a/test/e2e/setup/playwright.setup.ts +++ b/test/e2e/setup/playwright.setup.ts @@ -68,13 +68,19 @@ export default async function globalSetup(config: FullConfig) { // create the catalog try { - await createCatalog(testConfiguration, projectNames, options.manualTestConfig); + await createCatalog(testConfiguration, projectNames, options.mainSpecName, options.manualTestConfig); } catch (exp) { throw exp; } // take care of chaise-config - copyChaiseConfig(options.chaiseConfigFilePath); + let chaiseConfigFilePath = options.chaiseConfigFilePath; + // use the default + if (typeof chaiseConfigFilePath !== 'string') { + chaiseConfigFilePath = `test/e2e/specs/${options.mainSpecName}/chaise-config.js`; + } + + copyChaiseConfig(chaiseConfigFilePath); registerCallbacks(testConfiguration); } @@ -119,7 +125,7 @@ async function checkUserSessions(): Promise<{ session: any, authCookie: string } /** * create the catalog and data */ -async function createCatalog(testConfiguration: any, projectNames: string[], isManual?: boolean) { +async function createCatalog(testConfiguration: any, projectNames: string[], mainSpecName: string, isManual?: boolean) { return new Promise(async (resolve, reject) => { testConfiguration.setup.url = process.env.ERMREST_URL; @@ -174,7 +180,9 @@ async function createCatalog(testConfiguration: any, projectNames: string[], isM for (const p of projectNames) { try { - const res = await setupCatalog({ catalog, schemas }); + // add alias to the catalog based on the config and project name + const alias = `${mainSpecName}-${p}`; + const res = await setupCatalog({ catalog: { ...catalog, alias }, schemas }); console.log(`catalog with id ${res.catalogId} created for project ${p}`); setCatalogID(p, res.catalogId); diff --git a/test/e2e/specs/all-features-confirmation/chaise-config.js b/test/e2e/specs/all-features-confirmation/chaise-config.js index b14c889ae..8d8366748 100644 --- a/test/e2e/specs/all-features-confirmation/chaise-config.js +++ b/test/e2e/specs/all-features-confirmation/chaise-config.js @@ -114,7 +114,3 @@ var chaiseConfig = { ] } }; - -if (typeof module === 'object' && module.exports && typeof require === 'function') { - exports.config = chaiseConfig; -} diff --git a/test/e2e/specs/all-features-confirmation/errors/errors.config.ts b/test/e2e/specs/all-features-confirmation/errors/errors.config.ts index b624cc245..13f0e5865 100644 --- a/test/e2e/specs/all-features-confirmation/errors/errors.config.ts +++ b/test/e2e/specs/all-features-confirmation/errors/errors.config.ts @@ -3,7 +3,7 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'all-features-confirmation/errors', configFileName: 'errors/dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features-confirmation/chaise-config.js', + mainSpecName: 'all-features-confirmation', testMatch: [ 'errors.spec.ts' ] diff --git a/test/e2e/specs/all-features-confirmation/footer/playwright.config.ts b/test/e2e/specs/all-features-confirmation/footer/playwright.config.ts index 8200f6b99..7fc840044 100644 --- a/test/e2e/specs/all-features-confirmation/footer/playwright.config.ts +++ b/test/e2e/specs/all-features-confirmation/footer/playwright.config.ts @@ -3,5 +3,5 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'all-features-confirmation/footer', configFileName: 'footer/dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features-confirmation/chaise-config.js', + mainSpecName: 'all-features-confirmation', }); diff --git a/test/e2e/specs/all-features-confirmation/navbar/playwright.config.ts b/test/e2e/specs/all-features-confirmation/navbar/playwright.config.ts index 1ee0f6196..6e4c4b260 100644 --- a/test/e2e/specs/all-features-confirmation/navbar/playwright.config.ts +++ b/test/e2e/specs/all-features-confirmation/navbar/playwright.config.ts @@ -3,5 +3,5 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'all-features-confirmation/navbar', configFileName: 'navbar/dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features-confirmation/chaise-config.js', + mainSpecName: 'all-features-confirmation', }); diff --git a/test/e2e/specs/all-features-confirmation/playwright.config.ts b/test/e2e/specs/all-features-confirmation/playwright.config.ts index 612446443..175e5e535 100644 --- a/test/e2e/specs/all-features-confirmation/playwright.config.ts +++ b/test/e2e/specs/all-features-confirmation/playwright.config.ts @@ -3,5 +3,5 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'all-features-confirmation', configFileName: 'parallel-configs/all-features-confirmation.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features-confirmation/chaise-config.js', + mainSpecName: 'all-features-confirmation', }); diff --git a/test/e2e/specs/all-features/navbar/playwright.config.ts b/test/e2e/specs/all-features/navbar/playwright.config.ts index bfcd9b335..62952f2ca 100644 --- a/test/e2e/specs/all-features/navbar/playwright.config.ts +++ b/test/e2e/specs/all-features/navbar/playwright.config.ts @@ -3,5 +3,5 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'all-features/navbar', configFileName: 'navbar/dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features/chaise-config.js', + mainSpecName: 'all-features', }); diff --git a/test/e2e/specs/all-features/permissions.config.ts b/test/e2e/specs/all-features/permissions.config.ts index 2e1207fe5..41086fed4 100644 --- a/test/e2e/specs/all-features/permissions.config.ts +++ b/test/e2e/specs/all-features/permissions.config.ts @@ -3,7 +3,7 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'all-features/permissions', configFileName: 'multi-permissions/dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features/chaise-config.js', + mainSpecName: 'all-features', testMatch: [ 'acls/main.spec.ts', '*/permissions-annotation.spec.ts' diff --git a/test/e2e/specs/all-features/playwright.config.ts b/test/e2e/specs/all-features/playwright.config.ts index 7d51235c2..60bb9ef92 100644 --- a/test/e2e/specs/all-features/playwright.config.ts +++ b/test/e2e/specs/all-features/playwright.config.ts @@ -3,6 +3,6 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'all-features', configFileName: 'parallel-configs/all-features.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features/chaise-config.js', + mainSpecName: 'all-features', runSequentially: true }); diff --git a/test/e2e/specs/all-features/record/copy-btn.config.ts b/test/e2e/specs/all-features/record/copy-btn.config.ts index acbe2e382..e860896a8 100644 --- a/test/e2e/specs/all-features/record/copy-btn.config.ts +++ b/test/e2e/specs/all-features/record/copy-btn.config.ts @@ -3,7 +3,7 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'all-features/record/copy-btn', configFileName: 'record/copy-btn.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features/chaise-config.js', + mainSpecName: 'all-features', testMatch: [ 'copy-btn.spec.ts' ] diff --git a/test/e2e/specs/all-features/record/related-table.config.ts b/test/e2e/specs/all-features/record/related-table.config.ts index 94b267013..ad97a35ee 100644 --- a/test/e2e/specs/all-features/record/related-table.config.ts +++ b/test/e2e/specs/all-features/record/related-table.config.ts @@ -4,5 +4,5 @@ export default getConfig({ testName: 'all-features/record/related-table', testMatch: 'related-table.spec.ts', configFileName: 'record/related-table/dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features/chaise-config.js', + mainSpecName: 'all-features', }); diff --git a/test/e2e/specs/all-features/recordedit/input-iframe.config.ts b/test/e2e/specs/all-features/recordedit/input-iframe.config.ts index ecc7cb98d..8ebb2dfac 100644 --- a/test/e2e/specs/all-features/recordedit/input-iframe.config.ts +++ b/test/e2e/specs/all-features/recordedit/input-iframe.config.ts @@ -3,7 +3,7 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'all-features/recordedit/input-iframe', configFileName: 'recordedit/input-iframe.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features/chaise-config.js', + mainSpecName: 'all-features', testMatch: [ 'input-iframe.spec.ts' ] diff --git a/test/e2e/specs/all-features/recordedit/input-iframe.spec.ts b/test/e2e/specs/all-features/recordedit/input-iframe.spec.ts index f25bfed6f..072724fb4 100644 --- a/test/e2e/specs/all-features/recordedit/input-iframe.spec.ts +++ b/test/e2e/specs/all-features/recordedit/input-iframe.spec.ts @@ -1,12 +1,11 @@ import { test, expect, TestInfo } from '@playwright/test'; -import { execSync } from 'child_process'; import { resolve } from 'path'; import RecordeditLocators, { RecordeditInputType } from '@isrd-isi-edu/chaise/test/e2e/locators/recordedit'; import ModalLocators from '@isrd-isi-edu/chaise/test/e2e/locators/modal'; import AlertLocators from '@isrd-isi-edu/chaise/test/e2e/locators/alert'; -import { getCatalogID } from '@isrd-isi-edu/chaise/test/e2e/utils/catalog-utils'; +import { copyFileToChaiseDir, getCatalogID } from '@isrd-isi-edu/chaise/test/e2e/utils/catalog-utils'; import { setInputValue, testRecordeditColumnNames, testSubmission } from '@isrd-isi-edu/chaise/test/e2e/utils/recordedit-utils'; const testParams = { @@ -230,24 +229,7 @@ const getRecordeditURL = (baseURL: string | undefined, testInfo: TestInfo, filte */ const copyIframeToLocation = () => { const iframeLocation = resolve(__dirname, './../../../utils/input-iframe-test.html'); - - const remoteChaiseDirPath = process.env.REMOTE_CHAISE_DIR_PATH; - // The tests will take this path when it is not running on CI and remoteChaseDirPath is not null - let cmd; - if (typeof remoteChaiseDirPath === 'string') { - cmd = `scp ${iframeLocation} ${remoteChaiseDirPath}/input-iframe-test.html`; - } else { - cmd = `sudo cp ${iframeLocation} /var/www/html/chaise/input-iframe-test.html`; - } - - try { - execSync(cmd); - console.log('copied the iframe into proper location'); - } catch (exp) { - console.log(exp); - console.log('Unable to copy the iframe into proper location'); - process.exit(1); - } + copyFileToChaiseDir(iframeLocation, 'input-iframe-test.html'); } const setIframeInputValues = async (iframeElementProps: any, values: any) => { diff --git a/test/e2e/specs/all-features/recordset/saved-query.config.ts b/test/e2e/specs/all-features/recordset/saved-query.config.ts index 199a349a7..798ab0a3e 100644 --- a/test/e2e/specs/all-features/recordset/saved-query.config.ts +++ b/test/e2e/specs/all-features/recordset/saved-query.config.ts @@ -3,6 +3,6 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'all-features/recordset/saved-query', configFileName: 'recordset/saved-query.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/all-features/chaise-config.js', + mainSpecName: 'all-features', testMatch: [ 'saved-query.spec.ts' ] -}); \ No newline at end of file +}); diff --git a/test/e2e/specs/default-config/chaise-config.js b/test/e2e/specs/default-config/chaise-config.js index 764eef154..1443249cb 100644 --- a/test/e2e/specs/default-config/chaise-config.js +++ b/test/e2e/specs/default-config/chaise-config.js @@ -5,7 +5,3 @@ var chaiseConfig = { logClientActions: false, hideRecordeditLeaveAlert: true, }; - -if (typeof module === 'object' && module.exports && typeof require === 'function') { - exports.config = chaiseConfig; -} diff --git a/test/e2e/specs/default-config/multi-form-input/multi-form-input.config.ts b/test/e2e/specs/default-config/multi-form-input/multi-form-input.config.ts index d1ea39cb9..78169c6d2 100644 --- a/test/e2e/specs/default-config/multi-form-input/multi-form-input.config.ts +++ b/test/e2e/specs/default-config/multi-form-input/multi-form-input.config.ts @@ -8,5 +8,5 @@ export default getConfig({ 'multi-form-input-edit.spec.ts' ], configFileName: 'recordedit/multi-form-input.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/default-config/chaise-config.js', + mainSpecName: 'default-config', }); diff --git a/test/e2e/specs/default-config/playwright.config.ts b/test/e2e/specs/default-config/playwright.config.ts index a37aac653..8cc76867e 100644 --- a/test/e2e/specs/default-config/playwright.config.ts +++ b/test/e2e/specs/default-config/playwright.config.ts @@ -3,5 +3,5 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'default-config', configFileName: 'parallel-configs/default-config.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/default-config/chaise-config.js', + mainSpecName: 'default-config', }); diff --git a/test/e2e/specs/default-config/record/links.conf.js b/test/e2e/specs/default-config/record/links.conf.js deleted file mode 100644 index 5bc46050f..000000000 --- a/test/e2e/specs/default-config/record/links.conf.js +++ /dev/null @@ -1,15 +0,0 @@ -var pConfig = require('./../../../utils/protractor.configuration.js'); - -var config = pConfig.getConfig({ - configFileName: 'record/links.dev.json', - specs: [ - "links.spec.js" - ], - setBaseUrl: function(browser, data) { - browser.params.url = process.env.CHAISE_BASE_URL; - return browser.params.url; - }, - chaiseConfigFilePath: 'test/e2e/specs/default-config/chaise-config.js' -}); - -exports.config = config; diff --git a/test/e2e/specs/default-config/record/links.config.ts b/test/e2e/specs/default-config/record/links.config.ts new file mode 100644 index 000000000..e2bbb6985 --- /dev/null +++ b/test/e2e/specs/default-config/record/links.config.ts @@ -0,0 +1,10 @@ +import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configuration'; + +export default getConfig({ + testName: 'default-config/record/links', + configFileName: 'record/links.dev.json', + mainSpecName: 'default-config', + testMatch: [ + 'links.spec.ts' + ] +}); diff --git a/test/e2e/specs/default-config/record/links.spec.js b/test/e2e/specs/default-config/record/links.spec.js deleted file mode 100644 index c2db8165d..000000000 --- a/test/e2e/specs/default-config/record/links.spec.js +++ /dev/null @@ -1,250 +0,0 @@ -var chaisePage = require('../../../utils/chaise.page.js'); -var EC = protractor.ExpectedConditions; -var fs = require('fs'); -var recordSetHelpers = require('../../../utils/recordset-helpers.js'); -var testParams = { - table_name: "links-table", - key: { - name: "id", - value: "1", - operator: "=" - }, - file_names: [ - "links-table.csv", - "links-table_" + chaisePage.getEntityRow("links", "links-table", [{column: "id",value: "1"}]).RID + ".zip" - ], - headers: ["association_table"], - tocHeaders: ["Summary", "association_table (0)"] -}; - -describe('View existing record,', function() { - - describe("For table " + testParams.table_name + ",", function() { - - var table, record; - - beforeAll(function () { - var keys = []; - keys.push(testParams.key.name + testParams.key.operator + testParams.key.value); - var url = browser.params.url + "/record/#" + browser.params.catalogId + "/links:" + testParams.table_name + "/" + keys.join("&"); - chaisePage.navigate(url); - - chaisePage.recordPageReady(); - }); - - if (!process.env.CI) { - describe("regarding the export button, ", function () { - var exportBtn; - beforeAll(function () { - exportBtn = chaisePage.recordsetPage.getExportDropdown(); - // delete files that may have been downloaded before - console.log("delete existing files"); - recordSetHelpers.deleteDownloadedFiles(testParams.file_names); - }); - - it ("first option must be `This record (CSV)` and user should be able to download the file.", function (done) { - browser.wait(EC.elementToBeClickable(exportBtn)); - chaisePage.clickButton(exportBtn).then(function () { - var csvOption = chaisePage.recordsetPage.getExportOption("This record (CSV)"); - expect(csvOption.getText()).toBe("This record (CSV)"); - return chaisePage.clickButton(csvOption); - }).then(function () { - browser.wait(function() { - return fs.existsSync(process.env.PWD + "/test/e2e/" + testParams.file_names[0]); - }, browser.params.defaultTimeout).then(function () { - done(); - }, function () { - done.fail("csv was not downloaded"); - }); - }).catch(function (err) { - done.fail(err); - }); - }); - - it ("second option must be default `BDBag` and user should be able to download the file.", function (done) { - var exportModal = chaisePage.recordsetPage.getExportModal(); - browser.wait(EC.elementToBeClickable(exportBtn)); - exportBtn.click().then(function () { - var bagOption = chaisePage.recordsetPage.getExportOption("BDBag"); - expect(bagOption.getText()).toBe("BDBag"); - return bagOption.click(); - }).then(function () { - return chaisePage.waitForElement(exportModal); - }).then(function () { - return chaisePage.waitForElementInverse(exportModal); - }).then(function () { - browser.wait(function() { - return fs.existsSync(process.env.PWD + "/test/e2e/" + testParams.file_names[1]); - }, browser.params.defaultTimeout).then(function () { - done(); - }, function () { - done.fail("bag was not downloaded"); - }); - }).catch(function (err) { - done.fail(err); - }); - }); - - afterAll(function() { - // delete files that have been downloaded during tests - console.log("delete created files"); - recordSetHelpers.deleteDownloadedFiles(testParams.file_names); - }); - }); - } - - it("should hide the text column based on hide_column_header property of column-display annotation", function (done) { - browser.wait(function() { - return chaisePage.recordPage.getColumns().count().then(function(ct) { - return (ct == 3); - }); - }, browser.params.defaultTimeout); - - chaisePage.recordPage.getColumns().then(function (cols) { - // shown column headers - expect(cols[0].isDisplayed()).toBeTruthy("Column header is hidden for id column"); - expect(cols[2].isDisplayed()).toBeTruthy("Column header is hidden for int column"); - // hidden column headers - expect(cols[1].isDisplayed()).toBeFalsy("Column header is shown for text column"); - done(); - }).catch(function(err){ - console.log(err); - done.fail(); - }); - }); - - it ("should show the empty related association tables and table of contents on page load", function (done) { - browser.wait(function() { - return chaisePage.recordPage.getSidePanelHeadings().count().then(function(ct) { - return (ct == testParams.tocHeaders.length); - }); - }, browser.params.defaultTimeout); - chaisePage.recordPage.getSidePanelTableTitles().then(function (headings) { - headings.forEach(function (heading, idx) { - expect(heading.getText()).toEqual(testParams.tocHeaders[idx], "related table heading with index: " + idx + " in toc is incorrect"); - }) - }) - - expect(chaisePage.recordPage.getRelatedTableTitles()).toEqual(testParams.headers, "list of related table accordion headers is incorret"); - done(); - }); - - it ("The proper permalink (browser url) should appear in the share popup if resolverImplicitCatalog is undefined", function (done) { - var shareButton = chaisePage.recordPage.getShareButton(), - shareModal = chaisePage.recordPage.getShareModal(); - - browser.wait(EC.elementToBeClickable(shareButton)); - chaisePage.clickButton(shareButton).then(function () { - // wait for dialog to open - chaisePage.waitForElement(shareModal); - - return browser.getCurrentUrl(); - }).then(function (url) { - // change url - var permalink = browser.params.origin+"/id/"+browser.params.catalogId+"/"+chaisePage.getEntityRow("links", testParams.table_name, [{column: "id",value: "1"}]).RID; - expect(chaisePage.recordPage.getLiveLinkElement().getText()).toBe(permalink, "permalink url is incorrect"); - - return chaisePage.recordsetPage.getModalCloseBtn().click(); - }).then(function () { - done(); - }).catch(function(err){ - console.log(err); - done.fail(); - }); - }); - - it("Clicking the subtitle should redirect to recordset app", function(done) { - var subtitleLink = chaisePage.recordPage.getEntitySubTitleElement(); - - browser.wait(EC.elementToBeClickable(subtitleLink), browser.params.defaultTimeout); - - subtitleLink.click().then(function() { - return browser.driver.getCurrentUrl(); - }).then(function(url) { - expect(url.indexOf('recordset')).toBeGreaterThan(-1); - - chaisePage.recordsetPageReady(); - done(); - }).catch(function(err){ - console.log(err); - done.fail(); - }); - }); - - if (!process.env.CI) { - // resolver is only configured to work locally - it("Searching in go to RID input should navigate the user to the resolved record page matching that RID", function (done) { - var rid = chaisePage.getEntityRow("links", testParams.table_name, [{column: "id",value: "1"}]).RID; - - element(by.id('rid-search-input')).sendKeys(rid); - element(by.css('.rid-search .chaise-search-btn')).click().then(function () { - browser.wait(function() { - return browser.getAllWindowHandles().then(function(tabs) { - return (tabs.length == 2); - }); - }, browser.params.defaultTimeout); - - return browser.getAllWindowHandles(); - }).then(function (tabs) { - allWindows = tabs; - - return browser.switchTo().window(allWindows[1]); - }).then(function () { - - return browser.driver.getCurrentUrl(); - }).then(function (url) { - var newTabUrl = "chaise/record/#" + browser.params.catalogId + "/links:" + testParams.table_name + "/RID=" + rid; - - expect(url.indexOf(newTabUrl)).toBeGreaterThan(-1, "new tab url is not the right page"); - - done(); - }).catch(function (err) { - console.dir(err); - done.fail(); - }); - }); - } - }); -}); - -var inlineParams = { - table_name: "inline_table", - key: { - name: "id", - value: "1", - operator: "=" - }, - headers: ["inline_association_table"], - tocHeaders: ["Summary", "inline_association_table (0)"], -} -describe('View existing record for testing "show empty sections" heuristics,', function() { - - describe("For table " + inlineParams.table_name + ",", function() { - - beforeAll(function () { - var keys = []; - keys.push(inlineParams.key.name + inlineParams.key.operator + inlineParams.key.value); - var url = browser.params.url + "/record/#" + browser.params.catalogId + "/links:" + inlineParams.table_name + "/" + keys.join("&"); - chaisePage.navigate(url); - - chaisePage.waitForElement(element(by.css('.record-main-section-table'))); - }); - - - it ("should show the empty related association tables and table of contents on page load", function (done) { - browser.wait(function() { - return chaisePage.recordPage.getSidePanelHeadings().count().then(function(ct) { - return (ct == inlineParams.tocHeaders.length); - }); - }, browser.params.defaultTimeout); - chaisePage.recordPage.getSidePanelTableTitles().then(function (headings) { - headings.forEach(function (heading, idx) { - expect(heading.getText()).toEqual(inlineParams.tocHeaders[idx], "related table heading with index: " + idx + " in toc is incorrect"); - }) - }) - - expect(chaisePage.recordPage.getRelatedTableTitles()).toEqual(inlineParams.headers, "list of related table accordion headers is incorret"); - done(); - }); - }); -}); diff --git a/test/e2e/specs/default-config/record/links.spec.ts b/test/e2e/specs/default-config/record/links.spec.ts new file mode 100644 index 000000000..583857ee3 --- /dev/null +++ b/test/e2e/specs/default-config/record/links.spec.ts @@ -0,0 +1,152 @@ +import { test, expect, TestInfo, Page } from '@playwright/test'; +import RecordsetLocators from '@isrd-isi-edu/chaise/test/e2e/locators/recordset'; +import RecordLocators from '@isrd-isi-edu/chaise/test/e2e/locators/record'; +import ModalLocators from '@isrd-isi-edu/chaise/test/e2e/locators/modal'; +import NavbarLocators from '@isrd-isi-edu/chaise/test/e2e/locators/navbar'; +import ExportLocators from '@isrd-isi-edu/chaise/test/e2e/locators/export'; + +import { getCatalogID, getEntityRow } from '@isrd-isi-edu/chaise/test/e2e/utils/catalog-utils'; +import { clickAndVerifyDownload, clickNewTabLink, getPageURLOrigin } from '@isrd-isi-edu/chaise/test/e2e/utils/page-utils'; + +const testParams = { + table_name: 'links-table' +}; + +test.describe.configure({ mode: 'parallel' }); + +test.describe('links on the record page', () => { + test('The proper permalink should appear in the share popup if resolverImplicitCatalog is undefined', async ({ page, baseURL }, testInfo) => { + test.skip(!!process.env.CI, 'in CI the resolver server component is not configured and cannot be tested'); + + await goToPage(page, baseURL, testInfo, testParams.table_name, true); + + // open the share popup on the first tab + await RecordLocators.getShareButton(page).click(); + const shareCiteModal = ModalLocators.getShareCiteModal(page); + await expect.soft(shareCiteModal).toBeVisible(); + + const origin = await getPageURLOrigin(page); + const RIDVal = getEntityRow(testInfo, 'links', testParams.table_name, [{ column: 'id', value: '1' }]).RID; + const expectedURL = `${origin}/id/${getCatalogID(testInfo.project.name)}/${RIDVal}`; + await expect.soft(ModalLocators.getLiveLinkElement(shareCiteModal)).toHaveText(expectedURL); + + await ModalLocators.getCloseBtn(shareCiteModal).click(); + }); + + test('Clicking the subtitle should redirect to recordset app', async ({ page, baseURL }, testInfo) => { + await goToPage(page, baseURL, testInfo, testParams.table_name, true); + + await RecordLocators.getEntitySubTitleElement(page).click(); + await page.waitForURL('**/recordset/**'); + await RecordsetLocators.waitForRecordsetPageReady(page); + }); + + test('Searching in go to RID input should navigate the user to the resolved record page matching that RID', async ({ page, baseURL }, testInfo) => { + test.skip(!!process.env.CI, 'in CI the resolver server component is not configured and cannot be tested'); + + await goToPage(page, baseURL, testInfo, testParams.table_name, true); + + const RIDVal = getEntityRow(testInfo, 'links', testParams.table_name, [{ column: 'id', value: '1' }]).RID; + await NavbarLocators.getGoToRIDInput(page).clear(); + await NavbarLocators.getGoToRIDInput(page).fill(RIDVal); + const newPage = await clickNewTabLink(NavbarLocators.getGoToRIDButton(page)); + await newPage.waitForURL(`**/record/#${getCatalogID(testInfo.project.name)}/links:${testParams.table_name}/RID=${RIDVal}**`); + await newPage.close(); + }); + +}); + + +test.describe('show/hide empty section button state', () => { + test('for a table with a related association table that user can create', async ({ page, baseURL }, testInfo) => { + await goToPage(page, baseURL, testInfo, testParams.table_name); + + await test.step('should show the empty related association tables and table of contents on page load', async () => { + const tocHeaders = RecordLocators.getSidePanelHeadings(page); + await expect.soft(tocHeaders).toHaveCount(2); + await expect.soft(tocHeaders).toHaveText(['Summary', 'association_table (0)']); + + const headers = RecordLocators.getDisplayedRelatedTableTitles(page); + await expect.soft(headers).toHaveCount(1); + await expect.soft(headers).toHaveText(['association_table']); + }); + }); + + test('for a table with an inline association table that user can create', async ({ page, baseURL }, testInfo) => { + await goToPage(page, baseURL, testInfo, 'inline_table'); + + await test.step('should show the empty inline related association tables and table of contents on page load', async () => { + const tocHeaders = RecordLocators.getSidePanelHeadings(page); + await expect.soft(tocHeaders).toHaveCount(2); + await expect.soft(tocHeaders).toHaveText(['Summary', 'inline_association_table (0)']); + + const headers = RecordLocators.getDisplayedRelatedTableTitles(page); + await expect.soft(headers).toHaveCount(0); + + const el = RecordLocators.getEntityRelatedTable(page, 'inline_association_table'); + await expect.soft(el).toBeVisible(); + }) + }); +}); + + +test('export button', async ({ page, baseURL }, testInfo) => { + test.skip(!!process.env.CI, 'in CI the export server component is not configured and cannot be tested'); + + await goToPage(page, baseURL, testInfo, testParams.table_name); + + await test.step('first option must be `This record (CSV)` and user should be able to download the file.', async () => { + await ExportLocators.getExportDropdown(page).click(); + const option = ExportLocators.getExportOption(page, 'This record (CSV)'); + await expect.soft(option).toHaveText('This record (CSV)'); + + await clickAndVerifyDownload(option, 'links-table.csv'); + }); + + await test.step('second option must be default `BDBag` and user should be able to download the file.', async () => { + await ExportLocators.getExportDropdown(page).click(); + const option = ExportLocators.getExportOption(page, 'BDBag'); + await expect.soft(option).toHaveText('BDBag'); + + const filename = `links-table_${getEntityRow(testInfo, 'links', 'links-table', [{ column: 'id', value: '1' }]).RID}.zip`; + + await clickAndVerifyDownload(option, filename, async () => { + const exportModal = ModalLocators.getExportModal(page); + await expect.soft(exportModal).toBeVisible(); + await expect.soft(exportModal).not.toBeAttached(); + }); + }); + +}); + +test('hide_column_header support', async ({ page, baseURL }, testInfo) => { + await goToPage(page, baseURL, testInfo, testParams.table_name); + + await test.step('should hide the text column based on hide_column_header property of column-display annotation', async () => { + const columns = RecordLocators.getColumns(page); + await expect.soft(columns).toHaveCount(3); + + await expect.soft(columns.nth(0)).toBeVisible(); + + await expect.soft(columns.nth(1)).toBeHidden(); + + await expect.soft(columns.nth(2)).toBeVisible(); + }); +}); + + + + +/********************** helper functions ************************/ +const goToPage = async (page: Page, baseURL: string | undefined, testInfo: TestInfo, tableName: string, dontWrapAroundStep?: boolean) => { + const steps = async () => { + await page.goto(`${baseURL}/record/#${getCatalogID(testInfo.project.name)}/${tableName}/id=1`); + await RecordLocators.waitForRecordPageReady(page); + } + + if (dontWrapAroundStep) { + await steps(); + } else { + await test.step('should load the page properly', steps); + } +} diff --git a/test/e2e/specs/default-config/recordedit/composite-key.config.ts b/test/e2e/specs/default-config/recordedit/composite-key.config.ts index dfc58e0ee..55dbb4d5f 100644 --- a/test/e2e/specs/default-config/recordedit/composite-key.config.ts +++ b/test/e2e/specs/default-config/recordedit/composite-key.config.ts @@ -3,6 +3,6 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'default-config/recordedit/composite-key', configFileName: 'recordedit/composite-key.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/default-config/chaise-config.js', + mainSpecName: 'default-config', testMatch: [ 'composite-key.spec.ts' ] }); diff --git a/test/e2e/specs/default-config/recordedit/domain-filter.config.ts b/test/e2e/specs/default-config/recordedit/domain-filter.config.ts index a229df0d0..11421d187 100644 --- a/test/e2e/specs/default-config/recordedit/domain-filter.config.ts +++ b/test/e2e/specs/default-config/recordedit/domain-filter.config.ts @@ -3,6 +3,6 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'default-config/recordedit/domain-filter', configFileName: 'recordedit/domain-filter.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/default-config/chaise-config.js', + mainSpecName: 'default-config', testMatch: [ 'domain-filter.spec.ts' ] }); diff --git a/test/e2e/specs/default-config/recordedit/foreign-key-dropdown.config.ts b/test/e2e/specs/default-config/recordedit/foreign-key-dropdown.config.ts index 24044ef17..986ca6b7f 100644 --- a/test/e2e/specs/default-config/recordedit/foreign-key-dropdown.config.ts +++ b/test/e2e/specs/default-config/recordedit/foreign-key-dropdown.config.ts @@ -3,6 +3,6 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'default-config/recordedit/foreign-key-dropdown', configFileName: 'recordedit/foreign-key-dropdown.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/default-config/chaise-config.js', + mainSpecName: 'default-config', testMatch: [ 'foreign-key-dropdown.spec.ts' ] }); diff --git a/test/e2e/specs/delete-prohibited/chaise-config.js b/test/e2e/specs/delete-prohibited/chaise-config.js index 062a1f74a..0c57d8a3b 100644 --- a/test/e2e/specs/delete-prohibited/chaise-config.js +++ b/test/e2e/specs/delete-prohibited/chaise-config.js @@ -2,6 +2,7 @@ var chaiseConfig = { name: "Delete Prohibited", + defaultCatalog: 'delete-prohibited-chrome', editRecord: true, deleteRecord: false, showFaceting: true, @@ -20,7 +21,3 @@ var chaiseConfig = { markdownPattern: "This is a banner with [link](https://example.com)" } }; - -if (typeof module === 'object' && module.exports && typeof require === 'function') { - exports.config = chaiseConfig; -} diff --git a/test/e2e/specs/delete-prohibited/navbar/catalog-chaise-config.spec.ts b/test/e2e/specs/delete-prohibited/navbar/catalog-chaise-config.spec.ts index b527b7293..493a7df8d 100644 --- a/test/e2e/specs/delete-prohibited/navbar/catalog-chaise-config.spec.ts +++ b/test/e2e/specs/delete-prohibited/navbar/catalog-chaise-config.spec.ts @@ -1,58 +1,219 @@ -import { test, expect } from '@playwright/test'; +import { test, expect, Page, TestInfo } from '@playwright/test'; +import { resolve } from 'path'; +import { readFileSync, writeFileSync, unlinkSync } from 'fs'; import NavbarLocators from '@isrd-isi-edu/chaise/test/e2e/locators/navbar'; import RecordsetLocators from '@isrd-isi-edu/chaise/test/e2e/locators/recordset'; -import { getCatalogID } from '@isrd-isi-edu/chaise/test/e2e/utils/catalog-utils'; +import { copyFileToChaiseDir, getCatalogID } from '@isrd-isi-edu/chaise/test/e2e/utils/catalog-utils'; import { clickNewTabLink } from '@isrd-isi-edu/chaise/test/e2e/utils/page-utils'; +import { PW_PROJECT_NAMES } from '@isrd-isi-edu/chaise/test/e2e/utils/constants'; -test.describe('Navbar', () => { +const NAVBAR_TEST_W_DYNAMIC_DEPS = 'navbar-test-w-dynamic-deps.html'; +const NAVBAR_TEST_W_STATIC_DEPS = 'navbar-test-w-static-deps.html'; - test('when navbar is visible', async ({ page, baseURL }, testInfo) => { - const navbar = NavbarLocators.getContainer(page); - const loginMenuOption = NavbarLocators.getLoginMenuContainer(page); +/** + * NOTES: + * + * 1. Since we're testing "static" navbar on this spec, you must build chaise prior to running this test. the "static" + * pages are generated by referring to the content of "dist" folder. + * + * 2. while each test inside this describe is independent of the other ones, we cannot do fullyParalell here because of + * beforeAll and afterAll. We want beforeAll and afterAll to run only once, but when we use fullyParallel, + * those functions will be called by each worker. + * + * + */ +test.describe('Navbar with chaise-config annotation', () => { - await test.step('navbar should be visible on load.', async () => { - const PAGE_URL = `/recordset/#${getCatalogID(testInfo.project.name)}/catalog-config-navbar:config-table`; - await page.goto(`${baseURL}${PAGE_URL}`); - await expect.soft(navbar).toBeVisible(); - }); + // prepare the html files needed for testing + test.beforeAll(({ baseURL }, testInfo) => { + if (allowNavbarStaticTest(testInfo)) prepareNavbarFiles(baseURL); - await test.step('should display the right title from catalog annotation chaiseConfig.', async () => { - await expect.soft(NavbarLocators.getBrandText(page)).toHaveText('override test123'); - }); + prepareNavbarFiles(baseURL); + }); - await test.step('should not display a brand image/logo', async () => { - const brandImage = NavbarLocators.getBrandImage(page) - await expect.soft(brandImage).toBeVisible(); - await expect.soft(brandImage).toHaveAttribute('src', '../images/logo.png'); - }); + test('should hide the navbar bar if the hideNavbar query parameter is set to true', async ({ page, baseURL }, testInfo) => { + const PAGE_URL = `/recordset/#${getCatalogID(testInfo.project.name)}/catalog-config-navbar:config-table`; + await page.pause(); + await page.goto(`${baseURL}${PAGE_URL}?hideNavbar=true`); + await RecordsetLocators.waitForRecordsetPageReady(page); + await expect.soft(NavbarLocators.getContainer(page)).not.toBeAttached(); + }); - await test.step('should show a banner on top of the navbar', async () => { - const banner = NavbarLocators.getBannerContent('', page); - await expect.soft(banner).toBeVisible(); - await expect.soft(banner).toHaveText('This is a banner with link'); - }); + test('on a chaise page', async ({ page, baseURL }, testInfo) => { + await testNavbarFunctionalities(page, `${baseURL}/recordset/#${getCatalogID(testInfo.project.name)}/catalog-config-navbar:config-table`); + }); - await test.step('should show a link for the login information since chaiseConfig.loggedInMenu is an object', async () => { - await expect.soft(loginMenuOption).toHaveText('Outbound Profile Link') - }); + test('on a static page with dynamic navbar-dependencies', async ({ page, baseURL }, testInfo) => { + const res = allowNavbarStaticTest(testInfo); + test.skip(!res.condition, res.reason); + await testNavbarFunctionalities(page, `${baseURL}/${NAVBAR_TEST_W_DYNAMIC_DEPS}`, true); + }); - if (!process.env.CI) { - await test.step('should open a new tab when clicking the link for the login information', async () => { - const newPage = await clickNewTabLink(loginMenuOption); + test('on a static page with dynamic navbar-dependencies and hash fragments', async ({ page, baseURL }, testInfo) => { + const res = allowNavbarStaticTest(testInfo); + test.skip(!res.condition, res.reason); + await testNavbarFunctionalities(page, `${baseURL}/${NAVBAR_TEST_W_DYNAMIC_DEPS}#example-of-a-hash-fragment`, true); + }); - await newPage.close(); - }); - } + test('on a static page with dynamic navbar-dependencies and query parameters', async ({ page, baseURL }, testInfo) => { + const res = allowNavbarStaticTest(testInfo); + test.skip(!res.condition, res.reason); + await testNavbarFunctionalities(page, `${baseURL}/${NAVBAR_TEST_W_DYNAMIC_DEPS}?example-of-a-query-fragment=1`, true); }); - test('should hide the navbar bar if the hideNavbar query parameter is set to true', async ({ page, baseURL }, testInfo) => { - const PAGE_URL = `/recordset/#${getCatalogID(testInfo.project.name)}/catalog-config-navbar:config-table`; - await page.goto(`${baseURL}${PAGE_URL}?hideNavbar=true`); + test('on a static page with static navbar-dependencies', async ({ page, baseURL }, testInfo) => { + const res = allowNavbarStaticTest(testInfo); + test.skip(!res.condition, res.reason); + await testNavbarFunctionalities(page, `${baseURL}/${NAVBAR_TEST_W_STATIC_DEPS}`, true); + }); - await RecordsetLocators.waitForRecordsetPageReady(page); + test('on a static page with static navbar-dependencies and hash fragments', async ({ page, baseURL }, testInfo) => { + const res = allowNavbarStaticTest(testInfo); + test.skip(!res.condition, res.reason); + await testNavbarFunctionalities(page, `${baseURL}/${NAVBAR_TEST_W_STATIC_DEPS}#example-of-a-hash-fragment`, true); + }); - await expect.soft(NavbarLocators.getContainer(page)).not.toBeAttached(); + test('on a static page with static navbar-dependencies and query parameters', async ({ page, baseURL }, testInfo) => { + const res = allowNavbarStaticTest(testInfo); + test.skip(!res.condition, res.reason); + await testNavbarFunctionalities(page, `${baseURL}/${NAVBAR_TEST_W_STATIC_DEPS}?example-of-a-query-fragment=1`, true); }); + // remove the html files needed for testing + test.afterAll(({ }, testInfo) => { + if (allowNavbarStaticTest(testInfo)) removeExtraNavbarFiles(); + }); }); + +/********************** helper functions ************************/ +const TEST_UTILS_FOLDER = resolve(__dirname, './../../../utils'); +const NAVBAR_DEPENDENCIES = resolve(__dirname, './../../../../../dist/react/lib/navbar/navbar-dependencies.html'); +const REPLACE_STRING = ''; + +/** + * afterAll and beforeAll are called multiple times. these booleans will avoid creating/removing files multiple times + */ +let alreadyCreated = false; +let alreadyRemoved = false; + +/** + * since we're adding alias using the project name, we cannot run this test on all projects. + */ +const allowNavbarStaticTest = (testInfo: TestInfo) => { + return { + condition: testInfo.project.name === PW_PROJECT_NAMES.CHROME, + reason: 'defaultCatalog is based on the project name. so only running on chrome' + }; +} + +/** + * create the navbar files needed for static testing (it will generate the files and rsync to location) + */ +const prepareNavbarFiles = (baseURL?: string) => { + if (alreadyCreated) return; + alreadyCreated = true; + + try { + // get the template file + const navbarTemplateStr = readFileSync(resolve(TEST_UTILS_FOLDER, './navbar-test.html')).toString(); + if (!navbarTemplateStr) throw new Error('unable to find navbar-test.html'); + + createNavbarFile(navbarTemplateStr, NAVBAR_TEST_W_DYNAMIC_DEPS, + `` + ); + + // get the dependencies + const staticDependencies = readFileSync(NAVBAR_DEPENDENCIES).toString(); + if (!staticDependencies) throw new Error('unable to find navbar-dependencies.html'); + + createNavbarFile(navbarTemplateStr, NAVBAR_TEST_W_STATIC_DEPS, staticDependencies); + + } catch (err) { + console.log('something went wrong while creating the navbar test files'); + console.log(err); + } +}; + +/** + * + * @param navbarTemplateStr the content of the file + * @param filename the filename that we should use + * @param dependenciesStr the dependencies string that should replace the REPLACE_STRING + */ +const createNavbarFile = (navbarTemplateStr: string, filename: string, dependenciesStr: string) => { + // create the dynamic dep file + const dynamicDepsContent = navbarTemplateStr.replace(REPLACE_STRING, dependenciesStr); + const navbarTestFileWDynamicDeps = resolve(TEST_UTILS_FOLDER, `./${filename}`); + writeFileSync(navbarTestFileWDynamicDeps, dynamicDepsContent); + + // copy the file into location + copyFileToChaiseDir(navbarTestFileWDynamicDeps, filename); +} + + +/** + * remove the navbar files that were created. + * (will only create the local files and not the ones that were moved to the remote location) + */ +const removeExtraNavbarFiles = () => { + if (alreadyRemoved) return; + alreadyRemoved = true; + + try { + console.log('removing the files'); + unlinkSync(resolve(TEST_UTILS_FOLDER, `./${NAVBAR_TEST_W_STATIC_DEPS}`)); + unlinkSync(resolve(TEST_UTILS_FOLDER, `./${NAVBAR_TEST_W_DYNAMIC_DEPS}`)); + } catch (exp) { + console.log('something went wrong while removing the navbar test files') + console.log(exp); + } +} + + +/** + * make sure navbar shows up as expected. + * + * NOTE: on static sites the .../images/logo.png location doesn't work, so the brandImage will not be visible. + * + * @param {boolean?} isStatic whether this is a static page + */ +const testNavbarFunctionalities = async (page: Page, pageURL: string, isStatic?: boolean) => { + const navbar = NavbarLocators.getContainer(page); + const loginMenuOption = NavbarLocators.getLoginMenuContainer(page); + + await test.step('navbar should be visible on load.', async () => { + await page.goto(pageURL); + await expect(navbar).toBeVisible(); + }); + + await test.step('should display the right title from catalog annotation.', async () => { + await expect.soft(NavbarLocators.getBrandText(page)).toHaveText('override test123'); + }); + + await test.step('should use the brand image of catalog annotation', async () => { + const brandImage = NavbarLocators.getBrandImage(page) + await expect.soft(brandImage).toHaveAttribute('src', '../images/logo.png'); + if (!isStatic) { + await expect.soft(brandImage).toBeVisible(); + } + }); + + await test.step('should show a banner on top of the navbar', async () => { + const banner = NavbarLocators.getBannerContent('', page); + await expect.soft(banner).toBeVisible(); + await expect.soft(banner).toHaveText('This is a banner with link'); + }); + + await test.step('should show a link for the login information since chaiseConfig.loggedInMenu is an object', async () => { + await expect.soft(loginMenuOption).toHaveText('Outbound Profile Link') + }); + + if (!process.env.CI) { + await test.step('should open a new tab when clicking the link for the login information', async () => { + const newPage = await clickNewTabLink(loginMenuOption); + + await newPage.close(); + }); + } +} diff --git a/test/e2e/specs/delete-prohibited/navbar/playwright.config.ts b/test/e2e/specs/delete-prohibited/navbar/playwright.config.ts index 3d1e7229c..7dbe17c96 100644 --- a/test/e2e/specs/delete-prohibited/navbar/playwright.config.ts +++ b/test/e2e/specs/delete-prohibited/navbar/playwright.config.ts @@ -3,5 +3,5 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'delete-prohibited/navbar', configFileName: 'navbar/catalog-chaise-config.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/delete-prohibited/chaise-config.js', + mainSpecName: 'delete-prohibited', }); diff --git a/test/e2e/specs/delete-prohibited/playwright.config.ts b/test/e2e/specs/delete-prohibited/playwright.config.ts index 0db4766c1..8e883aa33 100644 --- a/test/e2e/specs/delete-prohibited/playwright.config.ts +++ b/test/e2e/specs/delete-prohibited/playwright.config.ts @@ -3,5 +3,5 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'delete-prohibited', configFileName: 'parallel-configs/delete-prohibited.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/delete-prohibited/chaise-config.js', + mainSpecName: 'delete-prohibited', }); diff --git a/test/e2e/specs/delete-prohibited/record/no-delete-btn.config.ts b/test/e2e/specs/delete-prohibited/record/no-delete-btn.config.ts index e64aa0322..e5790ad49 100644 --- a/test/e2e/specs/delete-prohibited/record/no-delete-btn.config.ts +++ b/test/e2e/specs/delete-prohibited/record/no-delete-btn.config.ts @@ -3,7 +3,7 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'delete-prohibited/record', configFileName: 'record/no-delete.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/delete-prohibited/chaise-config.js', + mainSpecName: 'delete-prohibited', testMatch: [ 'no-delete-btn.spec.ts' ] diff --git a/test/e2e/specs/delete-prohibited/recordset/histogram-facet.config.ts b/test/e2e/specs/delete-prohibited/recordset/histogram-facet.config.ts index 983a760b0..628cc55d4 100644 --- a/test/e2e/specs/delete-prohibited/recordset/histogram-facet.config.ts +++ b/test/e2e/specs/delete-prohibited/recordset/histogram-facet.config.ts @@ -3,8 +3,8 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'delete-prohibited/recordset/histogram-facet', configFileName: 'recordset/histogram-facet.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/delete-prohibited/chaise-config.js', - testMatch: [ + mainSpecName: 'delete-prohibited', + testMatch: [ 'histogram-facet.spec.ts' ] -}); \ No newline at end of file +}); diff --git a/test/e2e/specs/delete-prohibited/recordset/ind-facet.config.ts b/test/e2e/specs/delete-prohibited/recordset/ind-facet.config.ts index bfff8cd09..7695653eb 100644 --- a/test/e2e/specs/delete-prohibited/recordset/ind-facet.config.ts +++ b/test/e2e/specs/delete-prohibited/recordset/ind-facet.config.ts @@ -3,11 +3,11 @@ import getConfig from '@isrd-isi-edu/chaise/test/e2e/setup/playwright.configurat export default getConfig({ testName: 'delete-prohibited/recordset/ind-facet', configFileName: 'recordset/ind-facet.dev.json', - chaiseConfigFilePath: 'test/e2e/specs/delete-prohibited/chaise-config.js', - testMatch: [ + mainSpecName: 'delete-prohibited', + testMatch: [ 'facet-presentation.spec.ts', 'ind-facet.spec.ts', 'four-facet-selections.spec.ts', // 'misc-facet.spec.ts' ] -}); \ No newline at end of file +}); diff --git a/test/e2e/utils/catalog-utils.ts b/test/e2e/utils/catalog-utils.ts index 1ab6439af..e96059aba 100644 --- a/test/e2e/utils/catalog-utils.ts +++ b/test/e2e/utils/catalog-utils.ts @@ -1,4 +1,5 @@ import { readFileSync } from 'fs'; +import { execSync } from 'child_process'; import { TestInfo } from '@playwright/test'; import { isObjectAndNotNull } from '@isrd-isi-edu/chaise/src/utils/type-utils'; @@ -192,7 +193,7 @@ export const updateCatalogAnnotation = async (catalogId: string, annotation: any url: process.env.ERMREST_URL, id: catalogId }; - ermrestUtils.createOrModifyCatalog(catalogObj, annotation, null, process.env.AUTH_COOKIE).then(function () { + ermrestUtils.createOrModifyCatalog(catalogObj, process.env.AUTH_COOKIE, annotation, null).then(function () { resolve(); }).catch((err: any) => { console.log('error while trying to update catalog annotation'); @@ -202,3 +203,38 @@ export const updateCatalogAnnotation = async (catalogId: string, annotation: any }); } +export const updateCatalogAlias = async (catalogId: string, alias: string): Promise => { + return new Promise((resolve, reject) => { + const catalogObj = { + url: process.env.ERMREST_URL, + id: catalogId + }; + ermrestUtils.createOrModifyCatalog(catalogObj, process.env.AUTH_COOKIE, undefined, undefined, alias).then(function () { + resolve(); + }).catch((err: any) => { + console.log('error while trying to update catalog annotation'); + console.log(err); + reject(err); + }); + }); +} + +export const copyFileToChaiseDir = (fileLocation: string, destinationFilename: string) => { + const remoteChaiseDirPath = process.env.REMOTE_CHAISE_DIR_PATH; + // The tests will take this path when it is not running on CI and remoteChaseDirPath is not null + let cmd; + if (typeof remoteChaiseDirPath === 'string') { + cmd = `scp ${fileLocation} ${remoteChaiseDirPath}/${destinationFilename}`; + } else { + cmd = `sudo cp ${fileLocation} /var/www/html/chaise/${destinationFilename}`; + } + + try { + execSync(cmd); + console.log('copied the file into proper location'); + } catch (exp) { + console.log(exp); + console.log('Unable to copy the iframe into proper location'); + process.exit(1); + } +} diff --git a/test/e2e/utils/navbar-test.html b/test/e2e/utils/navbar-test.html new file mode 100644 index 000000000..8a93aab0d --- /dev/null +++ b/test/e2e/utils/navbar-test.html @@ -0,0 +1,12 @@ + + + + Navbar static site test + + + + + +

Navbar static site test

+ + diff --git a/test/e2e/utils/page-utils.ts b/test/e2e/utils/page-utils.ts index 4d2ec86ef..0c2dbb849 100644 --- a/test/e2e/utils/page-utils.ts +++ b/test/e2e/utils/page-utils.ts @@ -39,11 +39,16 @@ export async function clickNewTabLink(locator: Locator) { * click on the given element and verify that it initiated a download * @param locator the button that will be clicked * @param expectedFileName pass undefined if you don't want to test the actual file path and just test that something was downloaded. - * @param page the page object + * @param waitCond if the page takes some time to trigger the download, add the proper wait condition. */ -export async function clickAndVerifyDownload(locator: Locator, expectedFileName: string | undefined) { +export async function clickAndVerifyDownload(locator: Locator, expectedFileName: string | undefined, waitCond?: () => Promise) { const downloadPromise = locator.page().waitForEvent('download'); await locator.click(); + + if (waitCond) { + await waitCond(); + } + const download = await downloadPromise; const filename = download.suggestedFilename(); diff --git a/test/e2e/utils/protractor.import.js b/test/e2e/utils/protractor.import.js index 1766a7ce5..5cfc4f0cd 100644 --- a/test/e2e/utils/protractor.import.js +++ b/test/e2e/utils/protractor.import.js @@ -354,7 +354,7 @@ exports.updateCatalogAnnotation = function (catalogId, annotation) { id: catalogId }; - ermrestUtils.createOrModifyCatalog(catalogObj, annotation, null).then(function () { + ermrestUtils.createOrModifyCatalog(catalogObj, process.env.AUTH_COOKIE, annotation).then(function () { console.log("successfully updated the catalog annotation"); defer.resolve(); }).catch(function (err) { @@ -364,3 +364,22 @@ exports.updateCatalogAnnotation = function (catalogId, annotation) { }); return defer.promise; } + +exports.updateCatalogAlias = function (catalogId, alias) { + var defer = Q.defer(); + + var catalogObj = { + url: process.env.ERMREST_URL, + id: catalogId + }; + + ermrestUtils.createOrModifyCatalog(catalogObj, process.env.AUTH_COOKIE, undefined, undefined, alias).then(function () { + console.log("successfully updated the catalog annotation"); + defer.resolve(); + }).catch(function (err) { + console.log("error while trying to update catalog annotation"); + console.dir(err); + defer.reject(err); + }); + return defer.promise; +}