diff options
author | Scott Bell <scott@traclabs.com> | 2022-03-18 16:27:14 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-18 16:27:14 +0300 |
commit | 918ec3759fb633cf8180bfb56e69dea86f579a0a (patch) | |
tree | 18f17681134a3206c8594264b905c45407ea55b9 | |
parent | 55b3b3bba99b7ca23cb406a9f307129d745a4515 (diff) | |
parent | 492ff2fa64274b1cf711e7eea0ec0aef9b258df8 (diff) |
Merge branch 'master' into mct4879mct4879
-rw-r--r-- | .github/workflows/e2e-pr.yml | 2 | ||||
-rw-r--r-- | .github/workflows/e2e-visual.yml | 2 | ||||
-rw-r--r-- | e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js | 161 | ||||
-rw-r--r-- | e2e/tests/moveObjects.e2e.spec.js | 42 | ||||
-rw-r--r-- | e2e/tests/persistence/addNoneditableObject.js | 27 | ||||
-rw-r--r-- | e2e/tests/persistence/persistability.e2e.spec.js | 77 | ||||
-rw-r--r-- | e2e/tests/plugins/ExportAsJSON/exportAsJson.e2e.spec.js | 48 | ||||
-rw-r--r-- | e2e/tests/plugins/ImportAsJSON/importAsJson.e2e.spec.js | 46 | ||||
-rw-r--r-- | e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js | 69 | ||||
-rw-r--r-- | e2e/tests/visual/default.spec.js | 60 | ||||
-rw-r--r-- | package.json | 36 | ||||
-rw-r--r-- | src/api/forms/components/controls/NumberField.vue | 10 | ||||
-rw-r--r-- | src/api/forms/components/controls/TextAreaField.vue | 9 | ||||
-rw-r--r-- | src/api/forms/components/controls/TextField.vue | 9 | ||||
-rw-r--r-- | src/plugins/timeConductor/ConductorInputsFixed.vue | 2 |
15 files changed, 574 insertions, 26 deletions
diff --git a/.github/workflows/e2e-pr.yml b/.github/workflows/e2e-pr.yml index a79ae472e..ce279307b 100644 --- a/.github/workflows/e2e-pr.yml +++ b/.github/workflows/e2e-pr.yml @@ -30,7 +30,7 @@ jobs: - uses: actions/setup-node@v3 with: node-version: '16' - - run: npx playwright install-deps + - run: npx playwright@1.19.2 install - run: npm install - run: npm run test:e2e:full - name: Archive test results diff --git a/.github/workflows/e2e-visual.yml b/.github/workflows/e2e-visual.yml index 26163895e..28653e7c9 100644 --- a/.github/workflows/e2e-visual.yml +++ b/.github/workflows/e2e-visual.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/setup-node@v3 with: node-version: '16' - - run: npx playwright install-deps + - run: npx playwright@1.19.2 install - run: npm install - name: Run the e2e visual tests run: npm run test:e2e:visual diff --git a/e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js b/e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js new file mode 100644 index 000000000..fc8101c9e --- /dev/null +++ b/e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js @@ -0,0 +1,161 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +/* +This test suite is dedicated to tests which verify the basic operations surrounding conditionSets. +*/ + +const { test, expect } = require('@playwright/test'); + +test.describe('Sine Wave Generator', () => { + test('Create new Sine Wave Generator Object and validate create Form Logic', async ({ page }) => { + //Go to baseURL + await page.goto('/', { waitUntil: 'networkidle' }); + + //Click the Create button + await page.click('button:has-text("Create")'); + + // Click Sine Wave Generator + await page.click('text=Sine Wave Generator'); + + // Verify that the each required field has required indicator + // Title + await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(['c-form-row__state-indicator req']); + + // Verify that the Notes row does not have a required indicator + await expect(page.locator('.c-form__section div:nth-child(3) .form-row .c-form-row__state-indicator')).not.toContain('.req'); + + // Period + await expect(page.locator('.c-form__section div:nth-child(4) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator req']); + + // Amplitude + await expect(page.locator('.c-form__section div:nth-child(5) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator req']); + + // Offset + await expect(page.locator('.c-form__section div:nth-child(6) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator req']); + + // Data Rate + await expect(page.locator('.c-form__section div:nth-child(7) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator req']); + + // Phase + await expect(page.locator('.c-form__section div:nth-child(8) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator req']); + + // Randomness + await expect(page.locator('.c-form__section div:nth-child(9) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator req']); + + // Verify that by removing value from required text field shows invalid indicator + await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill(''); + await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(['c-form-row__state-indicator req invalid']); + + // Verify that by adding value to empty required text field changes invalid to valid indicator + await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill('non empty'); + await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(['c-form-row__state-indicator req valid']); + + // Verify that by removing value from required number field shows invalid indicator + await page.locator('.field.control.l-input-sm input').first().fill(''); + await expect(page.locator('.c-form__section div:nth-child(4) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator req invalid']); + + // Verify that by adding value to empty required number field changes invalid to valid indicator + await page.locator('.field.control.l-input-sm input').first().fill('3'); + await expect(page.locator('.c-form__section div:nth-child(4) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator req valid']); + + // Verify that can change value of number field by up/down arrows keys + // Click .field.control.l-input-sm input >> nth=0 + await page.locator('.field.control.l-input-sm input').first().click(); + // Press ArrowUp 3 times to change value from 3 to 6 + await page.locator('.field.control.l-input-sm input').first().press('ArrowUp'); + await page.locator('.field.control.l-input-sm input').first().press('ArrowUp'); + await page.locator('.field.control.l-input-sm input').first().press('ArrowUp'); + + const value = await page.locator('.field.control.l-input-sm input').first().inputValue(); + await expect(value).toBe('6'); + + // Click .c-form-row__state-indicator.grows + await page.locator('.c-form-row__state-indicator.grows').click(); + + // Click text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"] + await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').click(); + + // Click .c-form-row__state-indicator >> nth=0 + await page.locator('.c-form-row__state-indicator').first().click(); + + // Fill text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"] + await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill('New Sine Wave Generator'); + + // Double click div:nth-child(4) .form-row .c-form-row__controls + await page.locator('div:nth-child(4) .form-row .c-form-row__controls').dblclick(); + + // Click .field.control.l-input-sm input >> nth=0 + await page.locator('.field.control.l-input-sm input').first().click(); + + // Click div:nth-child(4) .form-row .c-form-row__state-indicator + await page.locator('div:nth-child(4) .form-row .c-form-row__state-indicator').click(); + + // Click .field.control.l-input-sm input >> nth=0 + await page.locator('.field.control.l-input-sm input').first().click(); + + // Click .field.control.l-input-sm input >> nth=0 + await page.locator('.field.control.l-input-sm input').first().click(); + + // Click div:nth-child(5) .form-row .c-form-row__controls .form-control .field input + await page.locator('div:nth-child(5) .form-row .c-form-row__controls .form-control .field input').click(); + + // Click div:nth-child(5) .form-row .c-form-row__controls .form-control .field input + await page.locator('div:nth-child(5) .form-row .c-form-row__controls .form-control .field input').click(); + + // Click div:nth-child(5) .form-row .c-form-row__controls .form-control .field input + await page.locator('div:nth-child(5) .form-row .c-form-row__controls .form-control .field input').click(); + + // Click div:nth-child(6) .form-row .c-form-row__controls .form-control .field input + await page.locator('div:nth-child(6) .form-row .c-form-row__controls .form-control .field input').click(); + + // Double click div:nth-child(7) .form-row .c-form-row__controls .form-control .field input + await page.locator('div:nth-child(7) .form-row .c-form-row__controls .form-control .field input').dblclick(); + + // Click div:nth-child(7) .form-row .c-form-row__state-indicator + await page.locator('div:nth-child(7) .form-row .c-form-row__state-indicator').click(); + + // Click div:nth-child(7) .form-row .c-form-row__controls .form-control .field input + await page.locator('div:nth-child(7) .form-row .c-form-row__controls .form-control .field input').click(); + + // Fill div:nth-child(7) .form-row .c-form-row__controls .form-control .field input + await page.locator('div:nth-child(7) .form-row .c-form-row__controls .form-control .field input').fill('3'); + + //Click text=OK + await Promise.all([ + page.waitForNavigation(), + page.click('text=OK') + ]); + + // Verify that the Sine Wave Generator is displayed and correct + // Verify object properties + await expect(page.locator('.l-browse-bar__object-name')).toContainText('New Sine Wave Generator'); + + // Verify canvas rendered + await page.locator('canvas').nth(1).click({ + position: { + x: 341, + y: 28 + } + }); + }); +}); diff --git a/e2e/tests/moveObjects.e2e.spec.js b/e2e/tests/moveObjects.e2e.spec.js new file mode 100644 index 000000000..26ffdcdff --- /dev/null +++ b/e2e/tests/moveObjects.e2e.spec.js @@ -0,0 +1,42 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +/* +This test suite is dedicated to tests which verify the basic operations surrounding moving objects. +*/ + +const { test, expect } = require('@playwright/test'); + +test.describe('Move item tests', () => { + test.fixme('Create a basic object and verify that it can be moved to another Folder', async ({ page }) => { + //Create and save Folder + //Create and save Domain Object + //Verify that the newly created domain object can be moved to Folder from Step 1. + //Verify that newly moved object appears in the correct point in Tree + //Verify that newly moved object appears correctly in Inspector panel + }); + test.fixme('Create a basic object and verify that it cannot be moved to object without Composition Provider', async ({ page }) => { + //Create and save Telemetry Object + //Create and save Domain Object + //Verify that the newly created domain object cannot be moved to Telemetry Object from step 1. + }); +}); diff --git a/e2e/tests/persistence/addNoneditableObject.js b/e2e/tests/persistence/addNoneditableObject.js new file mode 100644 index 000000000..55da25358 --- /dev/null +++ b/e2e/tests/persistence/addNoneditableObject.js @@ -0,0 +1,27 @@ +(function () { + document.addEventListener('DOMContentLoaded', () => { + const PERSISTENCE_KEY = 'persistence-tests'; + const openmct = window.openmct; + + openmct.objects.addRoot({ + namespace: PERSISTENCE_KEY, + key: PERSISTENCE_KEY + }); + + openmct.objects.addProvider(PERSISTENCE_KEY, { + get(identifier) { + if (identifier.key !== PERSISTENCE_KEY) { + return undefined; + } else { + return Promise.resolve({ + identifier, + type: 'folder', + name: 'Persistence Testing', + location: 'ROOT', + composition: [] + }); + } + } + }); + }); +}()); diff --git a/e2e/tests/persistence/persistability.e2e.spec.js b/e2e/tests/persistence/persistability.e2e.spec.js new file mode 100644 index 000000000..56e48e658 --- /dev/null +++ b/e2e/tests/persistence/persistability.e2e.spec.js @@ -0,0 +1,77 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +/* +This test suite is dedicated to tests which verify the basic operations surrounding conditionSets. +*/ + +const { test, expect } = require('@playwright/test'); +const path = require('path'); + +// https://github.com/nasa/openmct/issues/4323#issuecomment-1067282651 + +test.describe('Persistence operations', () => { + // add non persistable root item + test.beforeEach(async ({ page }) => { + // eslint-disable-next-line no-undef + await page.addInitScript({ path: path.join(__dirname, 'addNoneditableObject.js') }); + }); + + test('Persistability should be respected in the create form location field', async ({ page }) => { + // Go to baseURL + await page.goto('/', { waitUntil: 'networkidle' }); + + // Click the Create button + await page.click('button:has-text("Create")'); + + // Click text=Condition Set + await page.click('text=Condition Set'); + + // Click form[name="mctForm"] >> text=Persistence Testing + await page.locator('form[name="mctForm"] >> text=Persistence Testing').click(); + + // Check that "OK" button is disabled + const okButton = page.locator('button:has-text("OK")'); + await expect(okButton).toBeDisabled(); + }); + test('Non-persistable objects should not show persistence related actions', async ({ page }) => { + // Go to baseURL + await page.goto('/', { waitUntil: 'networkidle' }); + + // Click text=Persistence Testing >> nth=0 + await page.locator('text=Persistence Testing').first().click({ + button: 'right' + }); + + const menuOptions = page.locator('.c-menu ul'); + + await expect.soft(menuOptions).toContainText(['Open In New Tab', 'View', 'Create Link']); + await expect(menuOptions).not.toContainText(['Move', 'Duplicate', 'Remove', 'Add New Folder', 'Edit Properties...', 'Export as JSON', 'Import from JSON']); + }); + test.fixme('Cannot move a previously created domain object to non-peristable boject in Move Modal', async ({ page }) => { + //Create a domain object + //Save Domain object + //Move Object and verify that cannot select non-persistable object + //Move Object to My Items + //Verify successful move + }); +}); diff --git a/e2e/tests/plugins/ExportAsJSON/exportAsJson.e2e.spec.js b/e2e/tests/plugins/ExportAsJSON/exportAsJson.e2e.spec.js new file mode 100644 index 000000000..96c41c463 --- /dev/null +++ b/e2e/tests/plugins/ExportAsJSON/exportAsJson.e2e.spec.js @@ -0,0 +1,48 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +/* +This test suite is dedicated to tests which verify the basic operations surrounding exportAsJSON. +*/ + +const { test, expect } = require('@playwright/test'); + +test.describe('ExportAsJSON', () => { + test.fixme('Create a basic object and verify that it can be exported as JSON from Tree', async ({ page }) => { + //Create domain object + //Save Domain Object + //Verify that the newly created domain object can be exported as JSON from the Tree + }); + test.fixme('Create a basic object and verify that it can be exported as JSON from 3 dot menu', async ({ page }) => { + //Create domain object + //Save Domain Object + //Verify that the newly created domain object can be exported as JSON from the 3 dot menu + }); + test.fixme('Verify that a nested Object can be exported as JSON', async ({ page }) => { + // Create 2 objects with hierarchy + // Export as JSON + // Verify Hiearchy + }); + test.fixme('Verify that the ExportAsJSON dropdown does not appear for the item X', async ({ page }) => { + // Other than non-persistible objects + }); +}); diff --git a/e2e/tests/plugins/ImportAsJSON/importAsJson.e2e.spec.js b/e2e/tests/plugins/ImportAsJSON/importAsJson.e2e.spec.js new file mode 100644 index 000000000..7c8d0ab64 --- /dev/null +++ b/e2e/tests/plugins/ImportAsJSON/importAsJson.e2e.spec.js @@ -0,0 +1,46 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +/* +This test suite is dedicated to tests which verify the basic operations surrounding importAsJSON. +*/ + +const { test, expect } = require('@playwright/test'); + +test.describe('ExportAsJSON', () => { + test.fixme('Verify that domain object can be importAsJSON from Tree', async ({ page }) => { + //Verify that an testdata JSON file can be imported from Tree + //Verify correctness of imported domain object + }); + test.fixme('Verify that domain object can be importAsJSON from 3 dot menu on folder', async ({ page }) => { + //Verify that an testdata JSON file can be imported from 3 dot menu on folder domain object + //Verify correctness of imported domain object + }); + test.fixme('Verify that a nested Objects can be importAsJSON', async ({ page }) => { + // Testdata with hierarchy + // ImportAsJSON on Tree + // Verify Hierarchy + }); + test.fixme('Verify that the ImportAsJSON dropdown does not appear for the item X', async ({ page }) => { + // Other than non-persistible objects + }); +}); diff --git a/e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js b/e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js new file mode 100644 index 000000000..70fc8bae2 --- /dev/null +++ b/e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js @@ -0,0 +1,69 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +const { test, expect } = require('@playwright/test'); + +test.describe('Time counductor operations', () => { + test('validate start time does not exceeds end time', async ({ page }) => { + //Go to baseURL + await page.goto('/', { waitUntil: 'networkidle' }); + const year = new Date().getFullYear(); + + let startDate = 'xxxx-01-01 01:00:00.000Z'; + startDate = year + startDate.substring(4); + + let endDate = 'xxxx-01-01 02:00:00.000Z'; + endDate = year + endDate.substring(4); + + const startTimeLocator = page.locator('input[type="text"]').first(); + const endTimeLocator = page.locator('input[type="text"]').nth(1); + + // Click start time + await startTimeLocator.click(); + + // Click end time + await endTimeLocator.click(); + + await endTimeLocator.fill(endDate.toString()); + await startTimeLocator.fill(startDate.toString()); + + // invalid start date + startDate = (year + 1) + startDate.substring(4); + await startTimeLocator.fill(startDate.toString()); + await endTimeLocator.click(); + + const startDateValidityStatus = await startTimeLocator.evaluate((element) => element.checkValidity()); + expect(startDateValidityStatus).not.toBeTruthy(); + + // fix to valid start date + startDate = (year - 1) + startDate.substring(4); + await startTimeLocator.fill(startDate.toString()); + + // invalid end date + endDate = (year - 2) + endDate.substring(4); + await endTimeLocator.fill(endDate.toString()); + await startTimeLocator.click(); + + const endDateValidityStatus = await endTimeLocator.evaluate((element) => element.checkValidity()); + expect(endDateValidityStatus).not.toBeTruthy(); + }); +}); diff --git a/e2e/tests/visual/default.spec.js b/e2e/tests/visual/default.spec.js index 60bd8052f..2ad857f92 100644 --- a/e2e/tests/visual/default.spec.js +++ b/e2e/tests/visual/default.spec.js @@ -111,3 +111,63 @@ test('Visual - Default Condition Widget', async ({ page }) => { await page.waitForTimeout(VISUAL_GRACE_PERIOD); await percySnapshot(page, 'Default Condition Widget'); }); + +test('Visual - Time Conductor start time is less than end time', async ({ page }) => { + //Go to baseURL + await page.goto('/', { waitUntil: 'networkidle' }); + const year = new Date().getFullYear(); + + let startDate = 'xxxx-01-01 01:00:00.000Z'; + startDate = year + startDate.substring(4); + + let endDate = 'xxxx-01-01 02:00:00.000Z'; + endDate = year + endDate.substring(4); + + await page.locator('input[type="text"]').nth(1).fill(endDate.toString()); + await page.locator('input[type="text"]').first().fill(startDate.toString()); + + // verify no error msg + await page.waitForTimeout(VISUAL_GRACE_PERIOD); + await percySnapshot(page, 'Default Time conductor'); + + startDate = (year + 1) + startDate.substring(4); + await page.locator('input[type="text"]').first().fill(startDate.toString()); + await page.locator('input[type="text"]').nth(1).click(); + + // verify error msg for start time (unable to capture snapshot of popup) + await page.waitForTimeout(VISUAL_GRACE_PERIOD); + await percySnapshot(page, 'Start time error'); + + startDate = (year - 1) + startDate.substring(4); + await page.locator('input[type="text"]').first().fill(startDate.toString()); + + endDate = (year - 2) + endDate.substring(4); + await page.locator('input[type="text"]').nth(1).fill(endDate.toString()); + + await page.locator('input[type="text"]').first().click(); + + // verify error msg for end time (unable to capture snapshot of popup) + await page.waitForTimeout(VISUAL_GRACE_PERIOD); + await percySnapshot(page, 'End time error'); +}); + +test('Visual - Sine Wave Generator Form', async ({ page }) => { + //Go to baseURL + await page.goto('/', { waitUntil: 'networkidle' }); + + //Click the Create button + await page.click('button:has-text("Create")'); + + // Click text=Sine Wave Generator + await page.click('text=Sine Wave Generator'); + + await page.waitForTimeout(VISUAL_GRACE_PERIOD); + await percySnapshot(page, 'Default Sine Wave Generator Form'); + + await page.locator('.field.control.l-input-sm input').first().click(); + await page.locator('.field.control.l-input-sm input').first().fill(''); + + // Validate red x mark + await page.waitForTimeout(VISUAL_GRACE_PERIOD); + await percySnapshot(page, 'removed amplitude property value'); +}); diff --git a/package.json b/package.json index 8a3938b86..fadea1347 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "html-loader": "0.5.5", "html2canvas": "1.4.1", "imports-loader": "0.8.0", - "istanbul-instrumenter-loader": "^3.0.1", + "istanbul-instrumenter-loader": "3.0.1", "jasmine-core": "4.0.0", "jsdoc": "3.5.5", "karma": "6.3.15", @@ -43,36 +43,36 @@ "karma-junit-reporter": "2.0.1", "karma-sourcemap-loader": "0.3.8", "karma-spec-reporter": "0.0.33", - "karma-webpack": "^5.0.0", - "location-bar": "^3.0.1", - "lodash": "^4.17.12", + "karma-webpack": "5.0.0", + "location-bar": "3.0.1", + "lodash": "4.17.12", "mini-css-extract-plugin": "2.4.5", "moment": "2.29.1", - "moment-duration-format": "^2.2.2", + "moment-duration-format": "2.2.2", "moment-timezone": "0.5.28", - "node-bourbon": "^4.2.3", - "painterro": "^1.2.56", - "plotly.js-basic-dist": "^2.5.0", - "plotly.js-gl2d-dist": "^2.5.0", - "printj": "^1.2.1", - "raw-loader": "^0.5.1", - "request": "^2.69.0", + "node-bourbon": "4.2.3", + "painterro": "1.2.56", + "plotly.js-basic-dist": "2.5.0", + "plotly.js-gl2d-dist": "2.5.0", + "printj": "1.2.1", + "raw-loader": "0.5.1", + "request": "2.69.0", "resolve-url-loader": "4.0.0", "sass": "1.49.0", "sass-loader": "12.4.0", "sinon": "13.0.1", "style-loader": "^1.0.1", - "uuid": "^3.3.3", + "uuid": "3.3.3", "vue": "2.6.14", "vue-eslint-parser": "8.2.0", "vue-loader": "15.9.8", "vue-template-compiler": "2.6.14", "webpack": "5.68.0", "webpack-cli": "4.9.2", - "webpack-dev-middleware": "^3.1.3", - "webpack-hot-middleware": "^2.22.3", + "webpack-dev-middleware": "3.7.3", + "webpack-hot-middleware": "2.22.3", "webpack-merge": "5.8.0", - "zepto": "^1.2.0" + "zepto": "1.2.0" }, "scripts": { "clean": "rm -rf ./dist ./node_modules; rm package-lock.json", @@ -88,8 +88,8 @@ "test:debug": "cross-env NODE_ENV=debug karma start --no-single-run", "test:coverage": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" COVERAGE=true karma start --single-run", "test:coverage:firefox": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run --browsers=FirefoxHeadless", - "test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome smoke default condition.e2e", - "test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js", + "test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome smoke default condition timeConductor", + "test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome", "test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js default", "test:e2e:full": "npx playwright test --config=e2e/playwright-ci.config.js", "test:watch": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --no-single-run", diff --git a/src/api/forms/components/controls/NumberField.vue b/src/api/forms/components/controls/NumberField.vue index 6a8bfef5e..77a27795b 100644 --- a/src/api/forms/components/controls/NumberField.vue +++ b/src/api/forms/components/controls/NumberField.vue @@ -30,13 +30,15 @@ :min="model.min" :max="model.max" :step="model.step" - @blur="blur()" + @input="updateText()" > </span> </span> </template> <script> +import { throttle } from 'lodash'; + export default { props: { model: { @@ -49,8 +51,12 @@ export default { field: this.model.value }; }, + mounted() { + this.updateText = throttle(this.updateText.bind(this), 200); + }, methods: { - blur() { + updateText() { + console.log('updateText', this.field); const data = { model: this.model, value: this.field diff --git a/src/api/forms/components/controls/TextAreaField.vue b/src/api/forms/components/controls/TextAreaField.vue index f3a724c78..8b0dad0b8 100644 --- a/src/api/forms/components/controls/TextAreaField.vue +++ b/src/api/forms/components/controls/TextAreaField.vue @@ -28,7 +28,7 @@ <textarea v-model="field" type="text" :size="model.size" - @blur="blur()" + @input="updateText()" > </textarea> </span> @@ -36,6 +36,8 @@ </template> <script> +import { throttle } from 'lodash'; + export default { props: { model: { @@ -48,8 +50,11 @@ export default { field: this.model.value }; }, + mounted() { + this.updateText = throttle(this.updateText.bind(this), 500); + }, methods: { - blur() { + updateText() { const data = { model: this.model, value: this.field diff --git a/src/api/forms/components/controls/TextField.vue b/src/api/forms/components/controls/TextField.vue index b13c133c2..939e42375 100644 --- a/src/api/forms/components/controls/TextField.vue +++ b/src/api/forms/components/controls/TextField.vue @@ -28,13 +28,15 @@ <input v-model="field" type="text" :size="model.size" - @blur="blur()" + @input="updateText()" > </span> </span> </template> <script> +import { throttle } from 'lodash'; + export default { props: { model: { @@ -47,8 +49,11 @@ export default { field: this.model.value }; }, + mounted() { + this.updateText = throttle(this.updateText.bind(this), 500); + }, methods: { - blur() { + updateText() { const data = { model: this.model, value: this.field diff --git a/src/plugins/timeConductor/ConductorInputsFixed.vue b/src/plugins/timeConductor/ConductorInputsFixed.vue index a14a3ef96..8e3bddd3b 100644 --- a/src/plugins/timeConductor/ConductorInputsFixed.vue +++ b/src/plugins/timeConductor/ConductorInputsFixed.vue @@ -253,6 +253,8 @@ export default { input.title = ''; } + this.$refs.fixedDeltaInput.reportValidity(); + return validationResult.valid; }, startDateSelected(date) { |