diff --git a/.gitignore b/.gitignore index ab58cf437..2adaca1c0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ node_modules # test screenshots for web package test_results/ +test-results/ +playwright-report/ # dist directory should be included only in the Package but not Repository dist @@ -26,4 +28,6 @@ log.json eslint-results.sarif # junit test results -junit-tests.xml \ No newline at end of file +junit-tests.xml +packages/web-new/test-results +packages/web-new/playwright-report \ No newline at end of file diff --git a/packages/web-new/README.md b/packages/web-new/README.md index 464b528de..2f60e13fc 100644 --- a/packages/web-new/README.md +++ b/packages/web-new/README.md @@ -74,7 +74,7 @@ The `webpack.config.js` file is used to set up Webpack for the project. It manag - `optimization`: Contains settings for optimizing the build, including minimizing CSS using `CssMinimizerPlugin` -## Deployment +### 4. Deployment Requires [Lerna](https://www.npmjs.com/package/lerna) to be installed globally (`npm install -g lerna`). @@ -108,4 +108,19 @@ npm run dev ```sh npm run build npm run serve -``` \ No newline at end of file +``` + +### 5. Testing with Playwright + +To utilize the Playwright package for testing the application, you need to install it using `npm install` since it's not intended for production use. Additionally, to set up the supported browsers required for Playwright to run tests, you should execute the command `npx playwright install`. + +You can assess the visual appearance and functionality of the package in all browsers by running the command `npm run test`. This will execute all the tests in the supported browsers, and once the tests have finished, Playwright will host the reports at `http://localhost:9323`. + +If the reports aren't displayed automatically, you can also use the command `npx playwright show-report` to view the test results. + +For a more visual approach to writing and visualizing tests, you can use the command `npx playwright test --ui`. This command provides a visual interface that allows you to step through each part of the test and observe what occurs before, during, and after each step. + +Debugging can also be accomplished by running the Playwright test command with the `--debug` flag, like this: `npx playwright test --debug`. + +For additional information on how to run and debug tests, please refer to the [official Playwright website](https://playwright.dev/docs/running-tests). + diff --git a/packages/web-new/package-lock.json b/packages/web-new/package-lock.json index 6c2ea5b38..8785b8049 100644 --- a/packages/web-new/package-lock.json +++ b/packages/web-new/package-lock.json @@ -23,6 +23,7 @@ "devDependencies": { "@babel/core": "^7.22.9", "@babel/preset-env": "^7.22.9", + "@playwright/test": "^1.39.0", "babel-loader": "^9.1.3", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.8.1", @@ -1913,6 +1914,21 @@ "node": ">= 8" } }, + "node_modules/@playwright/test": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz", + "integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==", + "dev": true, + "dependencies": { + "playwright": "1.39.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.23", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", @@ -5952,6 +5968,50 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/playwright": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz", + "integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==", + "dev": true, + "dependencies": { + "playwright-core": "1.39.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz", + "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", diff --git a/packages/web-new/package.json b/packages/web-new/package.json index 57aaee92d..a40af23af 100644 --- a/packages/web-new/package.json +++ b/packages/web-new/package.json @@ -18,11 +18,14 @@ "build": "node external-scripts/generate-paths.js && webpack --mode production", "dev": "webpack serve --mode development", "serve": "node server/server.js", - "examples": "node external-scripts/generate-paths.js" + "examples": "node external-scripts/generate-paths.js", + "test": "npx playwright test --project=chromium --project=firefox", + "test-full": "npx playwright test" }, "devDependencies": { "@babel/core": "^7.22.9", "@babel/preset-env": "^7.22.9", + "@playwright/test": "^1.39.0", "babel-loader": "^9.1.3", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.8.1", diff --git a/packages/web-new/playwright.config.js b/packages/web-new/playwright.config.js new file mode 100644 index 000000000..9863ec7f7 --- /dev/null +++ b/packages/web-new/playwright.config.js @@ -0,0 +1,59 @@ +// @ts-check +const { defineConfig, devices } = require('@playwright/test'); + +// require('dotenv').config(); + +module.exports = defineConfig({ + testDir: './tests', + // Folder for test artifacts such as screenshots, videos, traces, etc. + outputDir: 'test-results', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: 'http://127.0.0.1:5100', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + { + name: 'Microsoft Edge', + use: { ...devices['Desktop Edge'], channel: 'msedge' }, + }, + { + name: 'Google Chrome', + use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + } + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'npm run serve', + url: 'http://127.0.0.1:5100', + reuseExistingServer: !process.env.CI, + }, +}); \ No newline at end of file diff --git a/packages/web-new/src/examples-paths/examples-paths.json b/packages/web-new/src/examples-paths/examples-paths.json index 3d3321bec..007d386d2 100644 --- a/packages/web-new/src/examples-paths/examples-paths.json +++ b/packages/web-new/src/examples-paths/examples-paths.json @@ -118,11 +118,6 @@ "description": "A simple Thing Description using CoAP. The target resource is specified in the Thing Description by the href member of a form and the request method (e.g., GET, PUT, POST, or DELETE) is specified using the cov:method member of a form.", "path": "https://raw.githubusercontent.com/eclipse-thingweb/playground/master/examples/td/5-protocols/CoAP-simple-td-no-defaults.td.jsonld" }, - "extended-forms-multiple-op.td.jsonld": { - "title": "Extended Forms Multiple op", - "description": "In the case of a forms entry that has multiple op values the usage of the htv:methodName is not permitted. A TD Processor will extend the multiple op values to separate forms entries and associates a single operation with the default assumption.", - "path": "https://raw.githubusercontent.com/eclipse-thingweb/playground/master/examples/td/5-protocols/extended-forms-multiple-op.td.jsonld" - }, "HTTP-readproperty.td.jsonld": { "title": "HTTP readproperty", "description": "This example shows the binding of the readproperty operation for the HTTP.", @@ -148,6 +143,11 @@ "description": "This example shows the minimal set of terms to configure a single coil reading using Modbus. Notice that the unitID is contained in the href as the first element of the path.", "path": "https://raw.githubusercontent.com/eclipse-thingweb/playground/master/examples/td/5-protocols/Modbus-single-coil.td.jsonld" }, + "extended-forms-multiple-op.td.jsonld": { + "title": "Extended Forms Multiple op", + "description": "In the case of a forms entry that has multiple op values the usage of the htv:methodName is not permitted. A TD Processor will extend the multiple op values to separate forms entries and associates a single operation with the default assumption.", + "path": "https://raw.githubusercontent.com/eclipse-thingweb/playground/master/examples/td/5-protocols/extended-forms-multiple-op.td.jsonld" + }, "subprotocol-longpoll.td.jsonld": { "title": "Subprotocol Longpoll", "description": "protocols may have defined Subprotocols that can be used for some interaction types. For example, to receive asynchronous notifications using HTTP, some servers may support long polling.", @@ -158,6 +158,11 @@ "6-security-schemas": { "description": "This category contains various examples concerning the different types of security schemas that could/should be used for a Thing Description, as well as the different ways to combine multiple security schemes.", "examples": { + "OAuth2-scopes.td.jsonld": { + "title": "OAuth2 Scopes", + "description": "OAuth 2.0 makes use of scopes. These are identifiers that may appear in tokens and must match with corresponding identifiers in a resource to allow access to that resource.", + "path": "https://raw.githubusercontent.com/eclipse-thingweb/playground/master/examples/td/6-security-schemas/OAuth2-scopes.td.jsonld" + }, "apikey-in-body-simplified.td.jsonld": { "title": "Apikey In Body Simplified", "description": "It is possbile to simplify how security parameters are included in the payload by using the feature that the location referenced by a JSON pointer in a body location will be automatically inserted if it does not exist.", @@ -207,11 +212,6 @@ "title": "noSec Security", "description": "Security configuration in the TD is mandatory, therefore the nosec security scheme is provided for the case that no security is needed.", "path": "https://raw.githubusercontent.com/eclipse-thingweb/playground/master/examples/td/6-security-schemas/noSec-security.td.jsonld" - }, - "OAuth2-scopes.td.jsonld": { - "title": "OAuth2 Scopes", - "description": "OAuth 2.0 makes use of scopes. These are identifiers that may appear in tokens and must match with corresponding identifiers in a resource to allow access to that resource.", - "path": "https://raw.githubusercontent.com/eclipse-thingweb/playground/master/examples/td/6-security-schemas/OAuth2-scopes.td.jsonld" } } }, diff --git a/packages/web-new/src/styles/_console.scss b/packages/web-new/src/styles/_console.scss index 7378a7ba9..adf0c425a 100644 --- a/packages/web-new/src/styles/_console.scss +++ b/packages/web-new/src/styles/_console.scss @@ -537,10 +537,12 @@ align-items: center; justify-content: space-between; gap: 1rem; + pointer-events: none; input, select { width: 100%; + pointer-events: all; } input[type="checkbox"] { diff --git a/packages/web-new/src/styles/styles.css b/packages/web-new/src/styles/styles.css index a36d94aa3..46f9da552 100644 --- a/packages/web-new/src/styles/styles.css +++ b/packages/web-new/src/styles/styles.css @@ -1316,10 +1316,12 @@ main .console { align-items: center; justify-content: space-between; gap: 1rem; + pointer-events: none; } .console__content .visualize-view .visualize-inputs__tree .vega-bind label input, .console__content .visualize-view .visualize-inputs__tree .vega-bind label select { width: 100%; + pointer-events: all; } .console__content .visualize-view .visualize-inputs__tree .vega-bind label input[type=checkbox] { -webkit-appearance: none; diff --git a/packages/web-new/src/styles/styles.css.map b/packages/web-new/src/styles/styles.css.map index 57582cec6..af56eeafb 100644 --- a/packages/web-new/src/styles/styles.css.map +++ b/packages/web-new/src/styles/styles.css.map @@ -1 +1 @@ -{"version":3,"sources":["styles.scss","styles.css","_editor.scss","_control-panel.scss","_console.scss","_settings-menu.scss","_examples-menu.scss","_save-menu.scss","_json-yaml-warning.scss","_jsonld-vis.scss"],"names":[],"mappings":"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","file":"styles.css"} \ No newline at end of file +{"version":3,"sources":["styles.scss","styles.css","_editor.scss","_control-panel.scss","_console.scss","_settings-menu.scss","_examples-menu.scss","_save-menu.scss","_json-yaml-warning.scss","_jsonld-vis.scss"],"names":[],"mappings":"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","file":"styles.css"} \ No newline at end of file diff --git a/packages/web-new/src/template.html b/packages/web-new/src/template.html index a7f8e9ebf..615194c3d 100644 --- a/packages/web-new/src/template.html +++ b/packages/web-new/src/template.html @@ -554,13 +554,17 @@

Preferences

diff --git a/packages/web-new/tests/test.spec.js b/packages/web-new/tests/test.spec.js new file mode 100644 index 000000000..524e9f6c7 --- /dev/null +++ b/packages/web-new/tests/test.spec.js @@ -0,0 +1,2270 @@ +const { test, expect } = require('@playwright/test'); + +//Open the playground app before any test is runned +test.beforeEach(async ({ page }) => { + await page.goto('/') +}); + +test.describe("Load initial state", () => { + test('Has title', async ({ page }) => { + await expect(page).toHaveTitle("TD Playground") + }) + + test('Has editor tab', async ({ page }) => { + const editorTab = page.locator('#tab') + await expect(editorTab).toHaveText("TDThing TemplateCloseCancel") + }) + + test('Has TD template', async ({ page }) => { + const editor = page.locator('#editor1').getByRole('code').locator('div').filter({ hasText: '"title": "Thing Template",' }).nth(4) + await expect(editor).toHaveText('"title": "Thing Template",') + }) + + test('Validation tab is checked', async ({ page }) => { + const validationTab = page.locator('#validation-tab') + await expect(validationTab).toBeChecked() + }) + + test('Validation view is opened', async ({ page }) => { + const validationView = page.locator('#validation-view') + await expect(validationView).toHaveClass("console-view validation-view") + }) + + test('JSON button is checked', async ({ page }) => { + const jsonBtn = page.locator('#file-type-json') + await expect(jsonBtn).toBeChecked() + }) +}) + +test.describe("Check all links", () => { + test("Check Thingweb logo link", async ({ page }) => { + const thingwebPromise = page.waitForEvent('popup') + await page.locator(".logo").click() + const thingwebPage = await thingwebPromise + await expect(thingwebPage).toHaveTitle("Eclipse Thingweb") + await expect(thingwebPage).toHaveURL("https://www.thingweb.io") + }) + + test("Check CLI link", async ({ page }) => { + const cliPromise = page.waitForEvent('popup') + await page.locator(".cli-link").click() + const cliPage = await cliPromise + await expect(cliPage).toHaveURL("https://github.com/eclipse-thingweb/playground/tree/master/packages/cli") + }) + + test("Check Github link", async ({ page }) => { + const githubPromise = page.waitForEvent('popup') + await page.locator(".git-link").click() + const githubPage = await githubPromise + await expect(githubPage).toHaveTitle(/GitHub - eclipse-thingweb/) + await expect(githubPage).toHaveURL("https://github.com/eclipse-thingweb/playground") + }) + + test("Check Thingweb footer link", async ({ page }) => { + await page.locator('#settings-btn').click() + const thingwebPromise = page.waitForEvent('popup') + await page.locator("#thingweb-link").click() + const thingwebPage = await thingwebPromise + await expect(thingwebPage).toHaveTitle("Eclipse Thingweb") + await expect(thingwebPage).toHaveURL("https://www.thingweb.io") + }) + + test("Check Eclipse footer link", async ({ page }) => { + await page.locator('#settings-btn').click() + const eclipsePromise = page.waitForEvent('popup') + await page.locator("#eclipse-link").click() + const eclipsePage = await eclipsePromise + await expect(eclipsePage).toHaveTitle("The Community for Open Collaboration and Innovation | The Eclipse Foundation") + await expect(eclipsePage).toHaveURL("https://www.eclipse.org") + }) + + test("Check privacy policy footer link", async ({ page }) => { + await page.locator('#settings-btn').click() + const privacyPromise = page.waitForEvent('popup') + await page.locator("#privacy-link").click() + const privacyPage = await privacyPromise + await expect(privacyPage).toHaveTitle("Eclipse Foundation Website Privacy Policy | The Eclipse Foundation") + await expect(privacyPage).toHaveURL("https://www.eclipse.org/legal/privacy.php") + }) + + test("Check terms of use footer link", async ({ page }) => { + await page.locator('#settings-btn').click() + const termsPromise = page.waitForEvent('popup') + await page.locator("#terms-link").click() + const termsPage = await termsPromise + await expect(termsPage).toHaveTitle("Eclipse.org Terms of Use | The Eclipse Foundation") + await expect(termsPage).toHaveURL("https://www.eclipse.org/legal/termsofuse.php") + }) + + test("Check copyright agent footer link", async ({ page }) => { + await page.locator('#settings-btn').click() + const copyrightPromise = page.waitForEvent('popup') + await page.locator("#copyright-link").click() + const copyrightPage = await copyrightPromise + await expect(copyrightPage).toHaveTitle("Copyright Agent | The Eclipse Foundation") + await expect(copyrightPage).toHaveURL("https://www.eclipse.org/legal/copyright.php") + }) + + test("Check legal footer link", async ({ page }) => { + await page.locator('#settings-btn').click() + const legalPromise = page.waitForEvent('popup') + await page.locator("#legal-link").click() + const legalPage = await legalPromise + await expect(legalPage).toHaveTitle("Eclipse Foundation Legal Resources | The Eclipse Foundation") + await expect(legalPage).toHaveURL("https://www.eclipse.org/legal/") + }) +}) + +test.describe("Editors and Tabs creation and deletion", () => { + test("Adding a new editor and closing it", async ({ page }) => { + const editorTabs = page.locator("#tab") + const editors = page.locator(".editor") + await expect(editorTabs).toHaveCount(1) + await expect(editors).toHaveCount(1) + + const initialTab = page.locator("#tab").nth(0) + await expect(initialTab).toHaveAttribute('data-tab-id', "1") + await expect(initialTab).toHaveText("TDThing TemplateCloseCancel") + await expect(initialTab).toHaveClass("active") + + const initialEditor = page.locator("#editor1") + await expect(initialEditor).toHaveAttribute('data-ide-id', "1") + await expect(initialEditor).toHaveClass("editor active") + + await page.locator("#ide-tab-add").click() + await expect(editorTabs).toHaveCount(2) + await expect(editors).toHaveCount(2) + + await expect(initialTab).toHaveClass("") + await expect(initialEditor).toHaveClass("editor") + + const secondTab = page.locator("#tab").nth(1) + await expect(secondTab).toHaveAttribute('data-tab-id', "2") + await expect(secondTab).toHaveText("TDThing TemplateCloseCancel") + await expect(secondTab).toHaveClass("active") + + const secondEditor = page.locator("#editor2") + await expect(secondEditor).toHaveAttribute('data-ide-id', "2") + await expect(secondEditor).toHaveClass("editor active") + + await page.locator("#tab").nth(1).locator(".close-tab").click() + await page.locator('#tab').nth(1).locator(".confirm-btns > .confirm-tab-close").click() + + await expect(editorTabs).toHaveCount(1) + await expect(editors).toHaveCount(1) + + await expect(initialTab).toHaveClass("active") + await expect(initialEditor).toHaveClass("editor active") + }) + + test("Opening an example and closing initial editor", async ({ page }) => { + const editorTabs = page.locator("#tab") + const editors = page.locator(".editor") + await expect(editorTabs).toHaveCount(1) + await expect(editors).toHaveCount(1) + + const initialTab = page.locator("#tab").nth(0) + await expect(initialTab).toHaveAttribute('data-tab-id', "1") + await expect(initialTab).toHaveText("TDThing TemplateCloseCancel") + await expect(initialTab).toHaveClass("active") + + const initialEditor = page.locator("#editor1") + await expect(initialEditor).toHaveAttribute('data-ide-id', "1") + await expect(initialEditor).toHaveClass("editor active") + + await page.locator("#examples-btn").click() + await page.locator(".example").nth(0).click() + await page.locator(".example").nth(0).getByRole("button", { name: /Apply/ }).click() + + await expect(editorTabs).toHaveCount(2) + await expect(editors).toHaveCount(2) + + await expect(initialTab).toHaveClass("") + await expect(initialEditor).toHaveClass("editor") + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveClass("editor active") + + await page.locator("#tab").nth(0).locator(".close-tab").click() + await page.locator('#tab').nth(0).locator(".confirm-btns > .confirm-tab-close").click() + + await expect(editorTabs).toHaveCount(1) + await expect(editors).toHaveCount(1) + }) +}) + +test.describe("JSON and YAML conversion", () => { + test("JSON to YAML and YAML to JSON", async ({ page }) => { + const editorTabs = page.locator("#tab") + const editors = page.locator(".editor") + await expect(editorTabs).toHaveCount(1) + await expect(editors).toHaveCount(1) + + const jsonYamlPopup = page.locator('.json-yaml-warning') + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning closed") + + const initialEditor = page.locator("#editor1") + const jsonBtn = page.locator('#file-type-json') + const yamlBtn = page.locator('#file-type-yaml') + + await expect(initialEditor).toHaveAttribute('data-mode-id', "json") + await expect(jsonBtn).toBeChecked({ checked: true }) + await expect(yamlBtn).toBeChecked({ checked: false }) + + await yamlBtn.click() + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning") + + await page.locator('#yaml-confirm-btn').click() + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning closed") + await expect(initialEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(jsonBtn).toBeChecked({ checked: false }) + await expect(yamlBtn).toBeChecked({ checked: true }) + + await jsonBtn.click() + await expect(initialEditor).toHaveAttribute('data-mode-id', "json") + await expect(jsonBtn).toBeChecked({ checked: true }) + await expect(yamlBtn).toBeChecked({ checked: false }) + }) + + test("Cancel YAML conversion", async ({ page }) => { + const editorTabs = page.locator("#tab") + const editors = page.locator(".editor") + await expect(editorTabs).toHaveCount(1) + await expect(editors).toHaveCount(1) + + const jsonYamlPopup = page.locator('.json-yaml-warning') + const initialEditor = page.locator("#editor1") + const jsonBtn = page.locator('#file-type-json') + const yamlBtn = page.locator('#file-type-yaml') + + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning closed") + await expect(initialEditor).toHaveAttribute('data-mode-id', "json") + await expect(jsonBtn).toBeChecked({ checked: true }) + await expect(yamlBtn).toBeChecked({ checked: false }) + + await yamlBtn.click() + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning") + + await page.locator('#yaml-cancel-btn').click() + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning closed") + await expect(initialEditor).toHaveAttribute('data-mode-id', "json") + await expect(jsonBtn).toBeChecked({ checked: true }) + await expect(yamlBtn).toBeChecked({ checked: false }) + }) +}) + + +test.describe("Examples menu functionality", () => { + test("Open and close examples menu", async ({ page }) => { + + await expect(page.getByRole('heading', { name: 'Simple Default' })).toBeVisible({ visible: false }) + await page.locator("#examples-btn").click() + + await expect(page.getByRole('heading', { name: 'Simple Default' })).toBeVisible({ visible: true }) + await page.locator(".examples-menu-container__close > i").click() + + await expect(page.getByRole('heading', { name: 'Simple Default' })).toBeVisible({ visible: false }) + }) + + test("Open Basic TD from quick access", async ({ page }) => { + + await page.locator("#examples-btn").click() + + const basicExample = page.locator(".example").filter({ hasText: 'Basic TD' }).nth(0) + await expect(basicExample).toHaveClass("example") + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).nth(0).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveClass("editor active") + + }) + + test("Open Basic TD from apply button", async ({ page }) => { + + await page.locator("#examples-btn").click() + + const basicExample = page.locator(".example").filter({ hasText: 'Basic TD' }).nth(0) + await basicExample.click() + await expect(basicExample).toHaveClass("example open") + + const applyBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).nth(0).getByRole("button").filter({ hasText: "Apply" }) + await applyBtn.click() + await expect(basicExample).toHaveClass("example") + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveClass("editor active") + }) + + test("Open Basic TD and close with cancel button", async ({ page }) => { + await page.locator("#examples-btn").click() + + const basicTDExample = page.locator(".example").filter({ hasText: 'Basic TD' }).nth(0) + await basicTDExample.click() + await expect(basicTDExample).toHaveClass("example open") + + const cancelBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).nth(0).getByRole("button").filter({ hasText: "Cancel" }) + await cancelBtn.click() + await expect(basicTDExample).toHaveClass("example") + }) + + test("Toggle between TD and TM examples", async ({ page }) => { + await page.locator("#examples-btn").click() + + const thingTypeToggle = page.locator('#thing-type-btn') + await expect(thingTypeToggle).toBeChecked({ checked: false }) + + await thingTypeToggle.click() + await expect(thingTypeToggle).toBeChecked({ checked: true }) + }) + + test("Open Basic TM and check for icon change in tab", async ({ page }) => { + await page.locator("#examples-btn").click() + + const thingTypeToggle = page.locator('#thing-type-btn') + await thingTypeToggle.click() + await expect(thingTypeToggle).toBeChecked({ checked: true }) + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TM' }).nth(1).getByRole("button").nth(0) + await quickAccessBtn.click() + + const tabIcon = page.locator("#tab").nth(1).locator(".tab-icon") + await expect(tabIcon).toHaveText("TM") + }) + + test("Go to versioning in TD category and open example from quick access", async ({ page }) => { + await page.locator("#examples-btn").click() + + const categoryDropDown = page.locator("#thing-category") + await categoryDropDown.selectOption('9-versioning') + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Versioning' }).nth(0).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + }) + + test("Go to Tm Optional in TM category and open example from quick access", async ({ page }) => { + await page.locator("#examples-btn").click() + + const thingTypeToggle = page.locator('#thing-type-btn') + await thingTypeToggle.click() + await expect(thingTypeToggle).toBeChecked({ checked: true }) + + const categoryDropDown = page.locator("#thing-category") + await categoryDropDown.selectOption('4-tm-optional') + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Optional Interaction Affordances' }).nth(0).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TMLamp ThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + }) + + test("Search for uriVariable in the TDs and open Combined URI variables in href example", async ({ page }) => { + await page.locator("#examples-btn").click() + + const searchInput = page.locator(".search-input") + searchInput.fill('uriVariables') + + const searchBtn = page.locator(".search-btn") + await searchBtn.click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Combined URI variables in href' }).nth(0).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyWeatherThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + }) + + test("Search for overwrite in the TMs and open Overwrite Existing Definitions example", async ({ page }) => { + await page.locator("#examples-btn").click() + + const thingTypeToggle = page.locator('#thing-type-btn') + await thingTypeToggle.click() + await expect(thingTypeToggle).toBeChecked({ checked: true }) + + const searchInput = page.locator(".search-input") + searchInput.fill('overwrite') + + const searchBtn = page.locator(".search-btn") + await searchBtn.click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Overwrite Existing Definitions' }).nth(1).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TMSmart Lamp ControlCloseCancel") + await expect(exampleTab).toHaveClass("active") + }) +}) + +test.describe("Save menu functionality", () => { + test("Open and close save menu", async ({ page }) => { + const saveMenu = page.locator(".save-menu") + await expect(saveMenu).toHaveClass("save-menu closed") + + await page.locator("#save-btn").click() + await expect(saveMenu).toHaveClass("save-menu") + + const closeMenu = page.locator(".save-menu-close > i") + await closeMenu.click() + await expect(saveMenu).toHaveClass("save-menu closed") + }) + + test("Open save menu with template thing and check for TD in menu title", async ({ page }) => { + const saveMenu = page.locator(".save-menu") + + await page.locator("#save-btn").click() + await expect(saveMenu).toHaveClass("save-menu") + + const titleThingType = page.locator(".save-menu-title > p > #thing-type-text") + await expect(titleThingType).toHaveText("TD") + }) + + test("Open TM examples check for TM in the save menu title", async ({ page }) => { + await page.locator("#examples-btn").click() + + const thingTypeToggle = page.locator('#thing-type-btn') + await thingTypeToggle.click() + await expect(thingTypeToggle).toBeChecked({ checked: true }) + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TM' }).nth(1).getByRole("button").nth(0) + await quickAccessBtn.click() + + const saveMenu = page.locator(".save-menu") + + await page.locator("#save-btn").click() + await expect(saveMenu).toHaveClass("save-menu") + + const titleThingType = page.locator(".save-menu-title > p > #thing-type-text") + await expect(titleThingType).toHaveText("TM") + }) + + test("Share and open in new tab functionality with an example", async ({ page }) => { + + await page.locator("#examples-btn").click() + + const basicExample = page.locator(".example").filter({ hasText: 'Basic TD' }).nth(0) + await expect(basicExample).toHaveClass("example") + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).nth(0).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const saveMenu = page.locator(".save-menu") + + await page.locator("#save-btn").click() + await expect(saveMenu).toHaveClass("save-menu") + + const openNewTab = page.locator("#open-url-tab") + await expect(openNewTab).toBeDisabled() + + const shareUrlInput = page.locator("#share-url-input") + await expect(shareUrlInput).toHaveText("") + + const shareUrlBtn = page.locator("#share-url-btn") + await shareUrlBtn.click() + + const newPlaygroundPromise = page.waitForEvent('popup') + await openNewTab.click() + const newPlaygroundPage = await newPlaygroundPromise + + await expect(newPlaygroundPage).toHaveTitle("TD Playground") + + const newPlaygroundTab = newPlaygroundPage.locator("#tab").nth(0) + await expect(newPlaygroundTab).toHaveAttribute('data-tab-id', "1") + await expect(newPlaygroundTab).toHaveText("TDMyLampThingCloseCancel") + await expect(newPlaygroundTab).toHaveClass("active") + + }) + + test("Open in ediTDor functionality", async ({ page }) => { + const saveMenu = page.locator(".save-menu") + + await page.locator("#save-btn").click() + await expect(saveMenu).toHaveClass("save-menu") + + const shareUrlInput = page.locator("#share-url-input") + await expect(shareUrlInput).toHaveText("") + + const openEditdorBtn = page.locator("#open-editdor-btn") + + const editdorPromise = page.waitForEvent('popup') + await openEditdorBtn.click() + const editdorPage = await editdorPromise + + await expect(editdorPage).toHaveTitle("ediTDor") + + const linkedTd = editdorPage.locator("#linkedTd > option") + await expect(linkedTd).toHaveText("Thing Template") + }) + + test("Download functionality", async ({ page }) => { + const saveMenu = page.locator(".save-menu") + + const exampleTab = page.locator("#tab").nth(0) + await expect(exampleTab).toHaveAttribute('data-tab-id', "1") + await expect(exampleTab).toHaveText("TDThing TemplateCloseCancel") + await expect(exampleTab).toHaveClass("active") + + await page.locator("#save-btn").click() + await expect(saveMenu).toHaveClass("save-menu") + + const downloadTdBtn = page.locator(".save-td__download") + + // Start waiting for download before clicking. + const downloadPromise = page.waitForEvent('download') + await downloadTdBtn.click() + const download = await downloadPromise + const expectedFilename = 'Thing-Template.json' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) + + //* The "Save as" functionality cannot be tested because it requires to open and interact with the file system wich Playwright cannot do +}) + +test.describe("Settings menu functionality", () => { + test("Opening and closing the settings menu", async ({ page }) => { + const settingsMenu = page.locator(".settings-menu") + await expect(settingsMenu).toHaveClass("settings-menu closed") + + await page.locator("#settings-btn").click() + await expect(settingsMenu).toHaveClass("settings-menu") + + const closeMenu = page.locator(".settings__close > i") + await closeMenu.click() + await expect(settingsMenu).toHaveClass("settings-menu closed") + }) + + test("Checking settings toggle buttons", async ({ page }) => { + const settingsMenu = page.locator(".settings-menu") + await expect(settingsMenu).toHaveClass("settings-menu closed") + + await page.locator("#settings-btn").click() + await expect(settingsMenu).toHaveClass("settings-menu") + + const autoValidate = page.locator("#auto-validate") + const validateJsonld = page.locator("#validate-jsonld") + const tmConformance = page.locator("#tm-conformance") + + await expect(autoValidate).toBeChecked({ checked: false }) + await expect(validateJsonld).toBeChecked({ checked: true }) + await expect(tmConformance).toBeChecked({ checked: true }) + }) + + test("Changing page theme", async ({ page }) => { + const playgroundSite = page.locator("html") + await expect(playgroundSite).toHaveClass("light-mode") + + const settingsMenu = page.locator(".settings-menu") + await expect(settingsMenu).toHaveClass("settings-menu closed") + + await page.locator("#settings-btn").click() + await expect(settingsMenu).toHaveClass("settings-menu") + + const themePicker = page.locator("#theme-picker") + await themePicker.selectOption('monochrome-mode') + await expect(playgroundSite).toHaveClass("monochrome-mode") + + await themePicker.selectOption('dark-mode') + await expect(playgroundSite).toHaveClass("dark-mode") + + await page.reload({ waitUntil: 'domcontentloaded' }) + await expect(playgroundSite).toHaveClass("dark-mode") + }) + + test("Changing font size", async ({ page }) => { + const settingsMenu = page.locator(".settings-menu") + await expect(settingsMenu).toHaveClass("settings-menu closed") + + await page.locator("#settings-btn").click() + await expect(settingsMenu).toHaveClass("settings-menu") + + const editorFontSize = page.locator(".editor-font-size") + await expect(editorFontSize).toHaveText("14") + + const fontSizeSlider = page.locator('#font-size') + await fontSizeSlider.click() + + await expect(editorFontSize).toHaveText("23") + + await page.reload({ waitUntil: 'domcontentloaded' }) + + await expect(settingsMenu).toHaveClass("settings-menu closed") + + await page.locator("#settings-btn").click() + await expect(settingsMenu).toHaveClass("settings-menu") + + await expect(editorFontSize).toHaveText("23") + }) + + test("Utilizing default settings", async ({ page }) => { + const playgroundSite = page.locator("html") + await expect(playgroundSite).toHaveClass("light-mode") + + const settingsMenu = page.locator(".settings-menu") + await expect(settingsMenu).toHaveClass("settings-menu closed") + + await page.locator("#settings-btn").click() + await expect(settingsMenu).toHaveClass("settings-menu") + + const themePicker = page.locator("#theme-picker") + await themePicker.selectOption('dark-mode') + await expect(playgroundSite).toHaveClass("dark-mode") + + const editorFontSize = page.locator(".editor-font-size") + await expect(editorFontSize).toHaveText("14") + + const fontSizeSlider = page.locator('#font-size') + await fontSizeSlider.click() + + await expect(editorFontSize).toHaveText("23") + + await page.reload({ waitUntil: 'domcontentloaded' }) + + await expect(settingsMenu).toHaveClass("settings-menu closed") + + await page.locator("#settings-btn").click() + await expect(settingsMenu).toHaveClass("settings-menu") + + await expect(playgroundSite).toHaveClass("dark-mode") + await expect(editorFontSize).toHaveText("23") + + const resetSettings = page.locator('.reset-settings') + await resetSettings.click() + + await expect(playgroundSite).toHaveClass("light-mode") + await expect(editorFontSize).toHaveText("14") + + await page.reload({ waitUntil: 'domcontentloaded' }) + + await expect(settingsMenu).toHaveClass("settings-menu closed") + + await page.locator("#settings-btn").click() + await expect(settingsMenu).toHaveClass("settings-menu") + + await expect(playgroundSite).toHaveClass("light-mode") + await expect(editorFontSize).toHaveText("14") + }) +}) + +test.describe("Validation view functionality", () => { + + test("Starting the validation with the main valiation button", async ({ page }) => { + + const validationTab = page.locator('#validation-tab') + const validationView = page.locator('#validation-view') + + await expect(validationTab).toBeChecked() + await expect(validationView).toHaveClass("console-view validation-view") + + const stateIcon = page.locator(".json-validation-section > .section-header > i").nth(0) + await expect(stateIcon).toHaveClass("fa-solid fa-circle") + + const validationBtn = page.locator("#validate-btn") + await validationBtn.click() + + //TODO: Find a better way to wait for this event to happen + await page.waitForTimeout(5000) + await expect(stateIcon).toHaveClass("fa-solid fa-circle-check") + }) + + test("Closing the default validation view and opening it again with the validation view tab", async ({ page }) => { + + const validationTab = page.locator('#validation-tab') + const validationView = page.locator('#validation-view') + + await expect(validationTab).toBeChecked() + await expect(validationView).toHaveClass("console-view validation-view") + + const trashBtn = page.locator(".trash") + await trashBtn.click() + + await expect(validationTab).toBeChecked({ checked: false }) + await expect(validationView).toHaveClass("console-view validation-view hidden") + + await validationTab.click() + + await expect(validationTab).toBeChecked({ checked: true }) + await expect(validationView).toHaveClass("console-view validation-view") + + const stateIcon = page.locator(".json-validation-section > .section-header > i").nth(0) + await expect(stateIcon).toHaveClass("fa-solid fa-circle-check") + }) + + test("Validating the 'All Defaults TD'", async ({ page }) => { + const validationTab = page.locator('#validation-tab') + const validationView = page.locator('#validation-view') + + await expect(validationTab).toBeChecked() + await expect(validationView).toHaveClass("console-view validation-view") + + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'All Default Values' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + await expect(validationTab).toBeChecked({ checked: false }) + await expect(validationView).toHaveClass("console-view validation-view hidden") + + const validationBtn = page.locator("#validate-btn") + await validationBtn.click() + + await expect(validationTab).toBeChecked({ checked: true }) + await expect(validationView).toHaveClass("console-view validation-view") + + //validation section + const jsonValidationSection = page.locator(".json-validation-section") + const jsonValidationSectionIcon = page.locator(".json-validation-section > .section-header > i").nth(0) + const jsonValidationSectionTxt = page.locator(".json-validation-section > .section-content > li") + + await jsonValidationSection.click() + await expect(jsonValidationSectionTxt).toHaveText("Validated Successfully") + await expect(jsonValidationSectionIcon).toHaveClass("fa-solid fa-circle-check") + + const jsonSchemaValidationSection = page.locator(".json-schema-validation-section") + const jsonSchemaValidationSectionIcon = page.locator(".json-schema-validation-section > .section-header > i").nth(0) + const jsonSchemaValidationSectionTxt = page.locator(".json-schema-validation-section > .section-content > li") + + await jsonSchemaValidationSection.click() + await expect(jsonSchemaValidationSectionTxt).toHaveText("Validated Successfully") + await expect(jsonSchemaValidationSectionIcon).toHaveClass("fa-solid fa-circle-check") + + const jsonSchemaDefaultsSection = page.locator(".json-schema-defaults-section") + const jsonSchemaDefaultsSectionIcon = page.locator(".json-schema-defaults-section > .section-header > i").nth(0) + const jsonSchemaDefaultsSectionTxt = page.locator(".json-schema-defaults-section > .section-content > li") + + await jsonSchemaDefaultsSection.click() + await expect(jsonSchemaDefaultsSectionTxt).toHaveText("Validated Successfully") + await expect(jsonSchemaDefaultsSectionIcon).toHaveClass("fa-solid fa-circle-check") + + const jsonlsValidationSection = page.locator(".jsonls-validation-section") + const jsonlsValidationSectionIcon = page.locator(".jsonls-validation-section > .section-header > i").nth(0) + const jsonlsValidationSectionTxt = page.locator(".jsonls-validation-section > .section-content > li") + + await jsonlsValidationSection.click() + await expect(jsonlsValidationSectionTxt).toHaveText("Validated Successfully") + await expect(jsonlsValidationSectionIcon).toHaveClass("fa-solid fa-circle-check") + + const additionalChecksSection = page.locator(".additional-checks-section") + const additionalChecksSectionIcon = page.locator(".additional-checks-section > .section-header > i").nth(0) + const additionalChecksSectionTxt = page.locator(".additional-checks-section > .section-content > li") + + await additionalChecksSection.click() + await expect(additionalChecksSectionTxt).toHaveText("Validated Successfully") + await expect(additionalChecksSectionIcon).toHaveClass("fa-solid fa-circle-check") + }) + + test("Validating the 'Basic TD'", async ({ page }) => { + const validationTab = page.locator('#validation-tab') + const validationView = page.locator('#validation-view') + + await expect(validationTab).toBeChecked() + await expect(validationView).toHaveClass("console-view validation-view") + + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + await expect(validationTab).toBeChecked({ checked: false }) + await expect(validationView).toHaveClass("console-view validation-view hidden") + + const validationBtn = page.locator("#validate-btn") + await validationBtn.click() + + await expect(validationTab).toBeChecked({ checked: true }) + await expect(validationView).toHaveClass("console-view validation-view") + + + //Validation section + const jsonValidationSection = page.locator(".json-validation-section") + const jsonValidationSectionIcon = page.locator(".json-validation-section > .section-header > i").nth(0) + const jsonValidationSectionTxt = page.locator(".json-validation-section > .section-content > li") + + await jsonValidationSection.click() + await expect(jsonValidationSectionTxt).toHaveText("Validated Successfully") + await expect(jsonValidationSectionIcon).toHaveClass("fa-solid fa-circle-check") + + const jsonSchemaValidationSection = page.locator(".json-schema-validation-section") + const jsonSchemaValidationSectionIcon = page.locator(".json-schema-validation-section > .section-header > i").nth(0) + const jsonSchemaValidationSectionTxt = page.locator(".json-schema-validation-section > .section-content > li") + + await jsonSchemaValidationSection.click() + await expect(jsonSchemaValidationSectionTxt).toHaveText("Validated Successfully") + await expect(jsonSchemaValidationSectionIcon).toHaveClass("fa-solid fa-circle-check") + + const jsonSchemaDefaultsSection = page.locator(".json-schema-defaults-section") + const jsonSchemaDefaultsSectionIcon = page.locator(".json-schema-defaults-section > .section-header > i").nth(0) + const jsonSchemaDefaultsSectionTxt = page.locator(".json-schema-defaults-section > .section-content > li").nth(0) + + await jsonSchemaDefaultsSection.click() + await expect(jsonSchemaDefaultsSectionTxt).toHaveText("Optional validation failed:") + await expect(jsonSchemaDefaultsSectionIcon).toHaveClass("fa-solid fa-circle-exclamation") + + const jsonlsValidationSection = page.locator(".jsonls-validation-section") + const jsonlsValidationSectionIcon = page.locator(".jsonls-validation-section > .section-header > i").nth(0) + const jsonlsValidationSectionTxt = page.locator(".jsonls-validation-section > .section-content > li") + + await jsonlsValidationSection.click() + await expect(jsonlsValidationSectionTxt).toHaveText("Validated Successfully") + await expect(jsonlsValidationSectionIcon).toHaveClass("fa-solid fa-circle-check") + + const additionalChecksSection = page.locator(".additional-checks-section") + const additionalChecksSectionIcon = page.locator(".additional-checks-section > .section-header > i").nth(0) + const additionalChecksSectionTxt = page.locator(".additional-checks-section > .section-content > li") + + await additionalChecksSection.click() + await expect(additionalChecksSectionTxt).toHaveText("Validated Successfully") + await expect(additionalChecksSectionIcon).toHaveClass("fa-solid fa-circle-check") + }) + + test("Validating the 'Basic TM'", async ({ page }) => { + + const validationTab = page.locator('#validation-tab') + const validationView = page.locator('#validation-view') + + await expect(validationTab).toBeChecked() + await expect(validationView).toHaveClass("console-view validation-view") + + await page.locator("#examples-btn").click() + + const thingTypeToggle = page.locator('#thing-type-btn') + await thingTypeToggle.click() + await expect(thingTypeToggle).toBeChecked({ checked: true }) + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TM' }).nth(1).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TMLamp ThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + await expect(validationTab).toBeChecked({ checked: false }) + await expect(validationView).toHaveClass("console-view validation-view hidden") + + const validationBtn = page.locator("#validate-btn") + await validationBtn.click() + + await expect(validationTab).toBeChecked({ checked: true }) + await expect(validationView).toHaveClass("console-view validation-view") + + //Validation section + const jsonValidationSection = page.locator(".json-validation-section") + const jsonValidationSectionIcon = page.locator(".json-validation-section > .section-header > i").nth(0) + const jsonValidationSectionTxt = page.locator(".json-validation-section > .section-content > li") + + await jsonValidationSection.click() + await expect(jsonValidationSectionTxt).toHaveText("Validated Successfully") + await expect(jsonValidationSectionIcon).toHaveClass("fa-solid fa-circle-check") + + const jsonSchemaValidationSection = page.locator(".json-schema-validation-section") + const jsonSchemaValidationSectionIcon = page.locator(".json-schema-validation-section > .section-header > i").nth(0) + const jsonSchemaValidationSectionTxt = page.locator(".json-schema-validation-section > .section-content > li") + + await jsonSchemaValidationSection.click() + await expect(jsonSchemaValidationSectionTxt).toHaveText("Validated Successfully") + await expect(jsonSchemaValidationSectionIcon).toHaveClass("fa-solid fa-circle-check") + + const jsonSchemaDefaultsSection = page.locator(".json-schema-defaults-section") + const jsonSchemaDefaultsSectionIcon = page.locator(".json-schema-defaults-section > .section-header > i").nth(0) + const jsonSchemaDefaultsSectionTxt = page.locator(".json-schema-defaults-section > .section-content > li").nth(0) + + await jsonSchemaDefaultsSection.click() + await expect(jsonSchemaDefaultsSectionTxt).toHaveText("A previous validation has failed or it is only available for Thing Descriptions") + await expect(jsonSchemaDefaultsSectionIcon).toHaveClass("fa-solid fa-circle") + + const jsonlsValidationSection = page.locator(".jsonls-validation-section") + const jsonlsValidationSectionIcon = page.locator(".jsonls-validation-section > .section-header > i").nth(0) + const jsonlsValidationSectionTxt = page.locator(".jsonls-validation-section > .section-content > li") + + await jsonlsValidationSection.click() + await expect(jsonlsValidationSectionTxt).toHaveText("Validated Successfully") + await expect(jsonlsValidationSectionIcon).toHaveClass("fa-solid fa-circle-check") + + const additionalChecksSection = page.locator(".additional-checks-section") + const additionalChecksSectionIcon = page.locator(".additional-checks-section > .section-header > i").nth(0) + const additionalChecksSectionTxt = page.locator(".additional-checks-section > .section-content > li") + + await additionalChecksSection.click() + await expect(additionalChecksSectionTxt).toHaveText("Validated Successfully") + await expect(additionalChecksSectionIcon).toHaveClass("fa-solid fa-circle-check") + }) + +}) + +test.describe("OpenAPI view functionality", () => { + test("Trying to open the OpenAPI view with a TD with no protocols and closing it", async ({ page }) => { + + const initialTab = page.locator("#tab").nth(0) + await expect(initialTab).toHaveAttribute('data-tab-id', "1") + await expect(initialTab).toHaveText("TDThing TemplateCloseCancel") + await expect(initialTab).toHaveClass("active") + + const openAPIView = page.locator('#open-api-view') + const consoleError = page.locator('#console-error') + const openAPITab = page.locator("#open-api-tab") + + await expect(openAPIView).toHaveClass("console-view open-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(openAPITab).toBeChecked({ checked: false }) + + await openAPITab.click() + + await expect(openAPITab).toBeChecked({ checked: true }) + await expect(openAPIView).toHaveClass("console-view open-api-view hidden") + await expect(page.locator(".console-error__txt")).toHaveText("Please insert a TD which uses HTTP!") + + const trashBtn = page.locator(".trash") + await trashBtn.click() + + await expect(openAPIView).toHaveClass("console-view open-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(openAPITab).toBeChecked({ checked: false }) + + }) + + test("Trying to open the OpenAPI view with a TM", async ({ page }) => { + + await page.locator("#examples-btn").click() + + const thingTypeToggle = page.locator('#thing-type-btn') + await thingTypeToggle.click() + await expect(thingTypeToggle).toBeChecked({ checked: true }) + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TM' }).nth(1).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TMLamp ThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const openAPIView = page.locator('#open-api-view') + const consoleError = page.locator('#console-error') + const openAPITab = page.locator("#open-api-tab") + + await expect(openAPIView).toHaveClass("console-view open-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(openAPITab).toBeChecked({ checked: false }) + + await openAPITab.click() + + await expect(openAPITab).toBeChecked({ checked: true }) + await expect(openAPIView).toHaveClass("console-view open-api-view hidden") + await expect(page.locator(".console-error__txt")).toHaveText("This function is only allowed for Thing Descriptions!") + + }) + + test("Open the OpenAPI view with the 'Basic TD' example", async ({ page }) => { + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + const openAPIView = page.locator('#open-api-view') + const consoleError = page.locator('#console-error') + const openAPITab = page.locator("#open-api-tab") + + await expect(openAPIView).toHaveClass("console-view open-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(openAPITab).toBeChecked({ checked: false }) + + await openAPITab.click() + + await expect(openAPITab).toBeChecked({ checked: true }) + await expect(openAPIView).toHaveClass("console-view open-api-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const openAPIEditor = page.locator('#open-api-container') + const openAPIContainer = openAPIEditor.getByRole('code').locator('div').filter({ hasText: '"openapi": "3.0.3",' }).nth(4) + + await expect(openAPIEditor).toHaveAttribute('data-mode-id', "json") + await expect(openAPIContainer).toHaveText('\"openapi\": \"3.0.3\",') + + const openAPIJsonBtn = page.locator('#open-api-json') + + await expect(openAPIJsonBtn).toBeDisabled() + + }) + + test("Open the OpenAPI view with the 'Basic TD' example as YAML", async ({ page }) => { + + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + + const jsonYamlPopup = page.locator('.json-yaml-warning') + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning closed") + + const jsonBtn = page.locator('#file-type-json') + const yamlBtn = page.locator('#file-type-yaml') + + await expect(jsonBtn).toBeChecked({ checked: true }) + await expect(yamlBtn).toBeChecked({ checked: false }) + + await yamlBtn.click() + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning") + + await page.locator('#yaml-confirm-btn').click() + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning closed") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(jsonBtn).toBeChecked({ checked: false }) + await expect(yamlBtn).toBeChecked({ checked: true }) + + const openAPIView = page.locator('#open-api-view') + const consoleError = page.locator('#console-error') + const openAPITab = page.locator("#open-api-tab") + + await expect(openAPIView).toHaveClass("console-view open-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(openAPITab).toBeChecked({ checked: false }) + + await openAPITab.click() + + await expect(openAPITab).toBeChecked({ checked: true }) + await expect(openAPIView).toHaveClass("console-view open-api-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const openAPIEditor = page.locator('#open-api-container') + const openAPIContainer = openAPIEditor.getByRole('code').locator('div').filter({ hasText: 'openapi: "3.0.3"' }).nth(4) + + await expect(openAPIEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(openAPIContainer).toHaveText('openapi: "3.0.3"') + + const openAPIYamlBtn = page.locator('#open-api-yaml') + await expect(openAPIYamlBtn).toBeDisabled() + + }) + + test("Open the OpenAPI view and change form JSON to YAML and from YAML to JSON", async ({ page }) => { + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + const openAPIView = page.locator('#open-api-view') + const consoleError = page.locator('#console-error') + const openAPITab = page.locator("#open-api-tab") + + await expect(openAPIView).toHaveClass("console-view open-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(openAPITab).toBeChecked({ checked: false }) + + await openAPITab.click() + + await expect(openAPITab).toBeChecked({ checked: true }) + await expect(openAPIView).toHaveClass("console-view open-api-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const openAPIEditor = page.locator('#open-api-container') + + await expect(openAPIEditor).toHaveAttribute('data-mode-id', "json") + + const openAPIJsonBtn = page.locator('#open-api-json') + const openAPIYamlBtn = page.locator('#open-api-yaml') + + await expect(openAPIJsonBtn).toBeDisabled() + + await openAPIYamlBtn.click() + + await expect(openAPIEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(openAPIYamlBtn).toBeDisabled() + + await openAPIJsonBtn.click() + + await expect(openAPIEditor).toHaveAttribute('data-mode-id', "json") + await expect(openAPIJsonBtn).toBeDisabled() + }) + + test("Open the OpenAPI view and downloading it as JSON", async ({ page }) => { + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + const openAPIView = page.locator('#open-api-view') + const consoleError = page.locator('#console-error') + const openAPITab = page.locator("#open-api-tab") + + await expect(openAPIView).toHaveClass("console-view open-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(openAPITab).toBeChecked({ checked: false }) + + await openAPITab.click() + + await expect(openAPITab).toBeChecked({ checked: true }) + await expect(openAPIView).toHaveClass("console-view open-api-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const openAPIEditor = page.locator('#open-api-container') + const openAPIContainer = openAPIEditor.getByRole('code').locator('div').filter({ hasText: '"openapi": "3.0.3",' }).nth(4) + + await expect(openAPIEditor).toHaveAttribute('data-mode-id', "json") + await expect(openAPIContainer).toHaveText('\"openapi\": \"3.0.3\",') + + const openAPIJsonBtn = page.locator('#open-api-json') + await expect(openAPIJsonBtn).toBeDisabled() + + // Start waiting for download before clicking. + const openAPIDownload = page.locator('#open-api-download') + const downloadPromise = page.waitForEvent('download') + await openAPIDownload.click() + const download = await downloadPromise + const expectedFilename = 'MyLampThing-OpenAPI.json' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) + + test("Open the OpenAPI view and downloading it as YAML", async ({ page }) => { + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + const openAPIView = page.locator('#open-api-view') + const consoleError = page.locator('#console-error') + const openAPITab = page.locator("#open-api-tab") + + await expect(openAPIView).toHaveClass("console-view open-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(openAPITab).toBeChecked({ checked: false }) + + await openAPITab.click() + + await expect(openAPITab).toBeChecked({ checked: true }) + await expect(openAPIView).toHaveClass("console-view open-api-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const openAPIEditor = page.locator('#open-api-container') + + await expect(openAPIEditor).toHaveAttribute('data-mode-id', "json") + + const openAPIJsonBtn = page.locator('#open-api-json') + const openAPIYamlBtn = page.locator('#open-api-yaml') + + await expect(openAPIJsonBtn).toBeDisabled() + + await openAPIYamlBtn.click() + + await expect(openAPIEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(openAPIYamlBtn).toBeDisabled() + + const openAPIContainer = openAPIEditor.getByRole('code').locator('div').filter({ hasText: 'openapi: 3.0.3' }).nth(4) + await expect(openAPIContainer).toHaveText('openapi: 3.0.3') + + // Start waiting for download before clicking. + const openAPIDownload = page.locator('#open-api-download') + const downloadPromise = page.waitForEvent('download') + await openAPIDownload.click() + const download = await downloadPromise + const expectedFilename = 'MyLampThing-OpenAPI.yaml' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) +}) + +test.describe("AsyncAPI view functionality", () => { + test("Trying to open the AsyncAPI view with a TD with no protocols and closing it", async ({ page }) => { + + const initialTab = page.locator("#tab").nth(0) + await expect(initialTab).toHaveAttribute('data-tab-id', "1") + await expect(initialTab).toHaveText("TDThing TemplateCloseCancel") + await expect(initialTab).toHaveClass("active") + + const AsyncAPIView = page.locator('#async-api-view') + const consoleError = page.locator('#console-error') + const AsyncAPITab = page.locator("#async-api-tab") + + await expect(AsyncAPIView).toHaveClass("console-view async-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AsyncAPITab).toBeChecked({ checked: false }) + + await AsyncAPITab.click() + + await expect(AsyncAPITab).toBeChecked({ checked: true }) + await expect(AsyncAPIView).toHaveClass("console-view async-api-view hidden") + await expect(page.locator(".console-error__txt")).toHaveText("Please insert a TD which uses MQTT!") + + const trashBtn = page.locator(".trash") + await trashBtn.click() + + await expect(AsyncAPIView).toHaveClass("console-view async-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AsyncAPITab).toBeChecked({ checked: false }) + + }) + + test("Trying to open the AsyncAPI view with a TM", async ({ page }) => { + + await page.locator("#examples-btn").click() + + const thingTypeToggle = page.locator('#thing-type-btn') + await thingTypeToggle.click() + await expect(thingTypeToggle).toBeChecked({ checked: true }) + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TM' }).nth(1).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TMLamp ThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const AsyncAPIView = page.locator('#async-api-view') + const consoleError = page.locator('#console-error') + const AsyncAPITab = page.locator("#async-api-tab") + + await expect(AsyncAPIView).toHaveClass("console-view async-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AsyncAPITab).toBeChecked({ checked: false }) + + await AsyncAPITab.click() + + await expect(AsyncAPITab).toBeChecked({ checked: true }) + await expect(AsyncAPIView).toHaveClass("console-view async-api-view hidden") + await expect(page.locator(".console-error__txt")).toHaveText("This function is only allowed for Thing Descriptions!") + + }) + + /** + * TODO: Do to a lack of examples that include the mqtt protocol this cannot be tested, nonetheless once + * TODO: this is added the code below should sufice with minimal adjustments + test("Open the AsyncAPI view with the '---' example", async ({ page }) => { + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: '---' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TD---CloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + const AsyncAPIView = page.locator('#async-api-view') + const consoleError = page.locator('#console-error') + const AsyncAPITab = page.locator("#async-api-tab") + + await expect(AsyncAPIView).toHaveClass("console-view async-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AsyncAPITab).toBeChecked({ checked: false }) + + await AsyncAPITab.click() + + await expect(AsyncAPITab).toBeChecked({ checked: true }) + await expect(AsyncAPIView).toHaveClass("console-view async-api-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const AsyncAPIEditor = page.locator('#async-api-container') + const AsyncAPIContainer = AsyncAPIEditor.getByRole('code').locator('div').filter({ hasText: '"asyncapi": "2.0.0",' }).nth(4) + + await expect(AsyncAPIEditor).toHaveAttribute('data-mode-id', "json") + await expect(AsyncAPIContainer).toHaveText('"asyncapi": "2.0.0",') + + const AsyncAPIJsonBtn = page.locator('#async-api-json') + + await expect(AsyncAPIJsonBtn).toBeDisabled() + + }) + + test("Open the AsyncAPI view with the '---' example as YAML", async ({ page }) => { + + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: '---' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TD---CloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + + const jsonYamlPopup = page.locator('.json-yaml-warning') + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning closed") + + const jsonBtn = page.locator('#file-type-json') + const yamlBtn = page.locator('#file-type-yaml') + + await expect(jsonBtn).toBeChecked({ checked: true }) + await expect(yamlBtn).toBeChecked({ checked: false }) + + await yamlBtn.click() + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning") + + await page.locator('#yaml-confirm-btn').click() + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning closed") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(jsonBtn).toBeChecked({ checked: false }) + await expect(yamlBtn).toBeChecked({ checked: true }) + + const AsyncAPIView = page.locator('#async-api-view') + const consoleError = page.locator('#console-error') + const AsyncAPITab = page.locator("#async-api-tab") + + await expect(AsyncAPIView).toHaveClass("console-view async-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AsyncAPITab).toBeChecked({ checked: false }) + + await AsyncAPITab.click() + + await expect(AsyncAPITab).toBeChecked({ checked: true }) + await expect(AsyncAPIView).toHaveClass("console-view async-api-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const AsyncAPIEditor = page.locator('#async-api-container') + const AsyncAPIContainer = AsyncAPIEditor.getByRole('code').locator('div').filter({ hasText: 'asyncapi: 2.0.0' }).nth(4) + + await expect(AsyncAPIEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(AsyncAPIContainer).toHaveText('asyncapi: 2.0.0') + + const AsyncAPIYamlBtn = page.locator('#async-api-yaml') + await expect(AsyncAPIYamlBtn).toBeDisabled() + + }) + + test("Open the AsyncAPI view and change form JSON to YAML and from YAML to JSON", async ({ page }) => { + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: '---' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TD---CloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + const AsyncAPIView = page.locator('#async-api-view') + const consoleError = page.locator('#console-error') + const AsyncAPITab = page.locator("#async-api-tab") + + await expect(AsyncAPIView).toHaveClass("console-view async-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AsyncAPITab).toBeChecked({ checked: false }) + + await AsyncAPITab.click() + + await expect(AsyncAPITab).toBeChecked({ checked: true }) + await expect(AsyncAPIView).toHaveClass("console-view async-api-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const AsyncAPIEditor = page.locator('#async-api-container') + + await expect(AsyncAPIEditor).toHaveAttribute('data-mode-id', "json") + + const AsyncAPIJsonBtn = page.locator('#async-api-json') + const AsyncAPIYamlBtn = page.locator('#async-api-yaml') + + await expect(AsyncAPIJsonBtn).toBeDisabled() + + await AsyncAPIYamlBtn.click() + + await expect(AsyncAPIEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(AsyncAPIYamlBtn).toBeDisabled() + + await AsyncAPIJsonBtn.click() + + await expect(AsyncAPIEditor).toHaveAttribute('data-mode-id', "json") + await expect(AsyncAPIJsonBtn).toBeDisabled() + }) + + test("Open the AsyncAPI view and downloading it as JSON", async ({ page }) => { + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: '---' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TD---CloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + const AsyncAPIView = page.locator('#async-api-view') + const consoleError = page.locator('#console-error') + const AsyncAPITab = page.locator("#async-api-tab") + + await expect(AsyncAPIView).toHaveClass("console-view async-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AsyncAPITab).toBeChecked({ checked: false }) + + await AsyncAPITab.click() + + await expect(AsyncAPITab).toBeChecked({ checked: true }) + await expect(AsyncAPIView).toHaveClass("console-view async-api-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const AsyncAPIEditor = page.locator('#async-api-container') + const AsyncAPIContainer = AsyncAPIEditor.getByRole('code').locator('div').filter({ hasText: '"asyncapi": "2.0.0",' }).nth(4) + + await expect(AsyncAPIEditor).toHaveAttribute('data-mode-id', "json") + await expect(AsyncAPIContainer).toHaveText('\"asyncapi\": \"2.0.0\",') + + const AsyncAPIJsonBtn = page.locator('#async-api-json') + await expect(AsyncAPIJsonBtn).toBeDisabled() + + // Start waiting for download before clicking. + const AsyncAPIDownload = page.locator('#async-api-download') + const downloadPromise = page.waitForEvent('download') + await AsyncAPIDownload.click() + const download = await downloadPromise + const expectedFilename = 'MyLampThing-AsyncAPI.json' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) + + test("Open the AsyncAPI view and downloading it as YAML", async ({ page }) => { + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: '---' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TD---CloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + const AsyncAPIView = page.locator('#async-api-view') + const consoleError = page.locator('#console-error') + const AsyncAPITab = page.locator("#async-api-tab") + + await expect(AsyncAPIView).toHaveClass("console-view async-api-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AsyncAPITab).toBeChecked({ checked: false }) + + await AsyncAPITab.click() + + await expect(AsyncAPITab).toBeChecked({ checked: true }) + await expect(AsyncAPIView).toHaveClass("console-view async-api-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const AsyncAPIEditor = page.locator('#async-api-container') + + await expect(AsyncAPIEditor).toHaveAttribute('data-mode-id', "json") + + const AsyncAPIJsonBtn = page.locator('#async-api-json') + const AsyncAPIYamlBtn = page.locator('#async-api-yaml') + + await expect(AsyncAPIJsonBtn).toBeDisabled() + + await AsyncAPIYamlBtn.click() + + await expect(AsyncAPIEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(AsyncAPIYamlBtn).toBeDisabled() + + const AsyncAPIContainer = AsyncAPIEditor.getByRole('code').locator('div').filter({ hasText: 'asyncapi: 2.0.0' }).nth(4) + await expect(AsyncAPIContainer).toHaveText('asyncapi: 2.0.0') + + // Start waiting for download before clicking. + const AsyncAPIDownload = page.locator('#async-api-download') + const downloadPromise = page.waitForEvent('download') + await AsyncAPIDownload.click() + const download = await downloadPromise + const expectedFilename = 'MyLampThing-AsyncAPI.yaml' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) + */ +}) + + +test.describe("AAS AID view functionality", () => { + test("Open the AAS view with a TD with no protocols and closing it", async ({ page }) => { + + const initialTab = page.locator("#tab").nth(0) + await expect(initialTab).toHaveAttribute('data-tab-id', "1") + await expect(initialTab).toHaveText("TDThing TemplateCloseCancel") + await expect(initialTab).toHaveClass("active") + + const AASView = page.locator('#aas-view') + const consoleError = page.locator('#console-error') + const AASTab = page.locator("#aas-tab") + + await expect(AASView).toHaveClass("console-view aas-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AASTab).toBeChecked({ checked: false }) + + await AASTab.click() + + await expect(AASTab).toBeChecked({ checked: true }) + await expect(AASView).toHaveClass("console-view aas-view") + + const trashBtn = page.locator(".trash") + await trashBtn.click() + + await expect(AASView).toHaveClass("console-view aas-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AASTab).toBeChecked({ checked: false }) + + }) + + test("Trying to open the AAS view with a TM", async ({ page }) => { + + await page.locator("#examples-btn").click() + + const thingTypeToggle = page.locator('#thing-type-btn') + await thingTypeToggle.click() + await expect(thingTypeToggle).toBeChecked({ checked: true }) + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TM' }).nth(1).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TMLamp ThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const AASView = page.locator('#aas-view') + const consoleError = page.locator('#console-error') + const AASTab = page.locator("#aas-tab") + + await expect(AASView).toHaveClass("console-view aas-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AASTab).toBeChecked({ checked: false }) + + await AASTab.click() + + await expect(AASTab).toBeChecked({ checked: true }) + await expect(AASView).toHaveClass("console-view aas-view hidden") + await expect(page.locator(".console-error__txt")).toHaveText("This function is only allowed for Thing Descriptions!") + + }) + + test("Open the AAS AID view with the 'Basic TD' example", async ({ page }) => { + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + const AASView = page.locator('#aas-view') + const consoleError = page.locator('#console-error') + const AASTab = page.locator("#aas-tab") + + await expect(AASView).toHaveClass("console-view aas-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AASTab).toBeChecked({ checked: false }) + + await AASTab.click() + + await expect(AASTab).toBeChecked({ checked: true }) + await expect(AASView).toHaveClass("console-view aas-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const ASSEditor = page.locator('#aas-container') + const ASSContainer = ASSEditor.getByRole('code').locator('div').filter({ hasText: '"idShort": "AssetInterfacesDescription",' }).nth(4) + + await expect(ASSEditor).toHaveAttribute('data-mode-id', "json") + await expect(ASSContainer).toHaveText('"idShort": "AssetInterfacesDescription",') + + }) + + test("Open the AAS AID view with the 'Basic TD' example and downloading it", async ({ page }) => { + await page.locator("#examples-btn").click() + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TD' }).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TDMyLampThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const exampleEditor = page.locator("#editor2") + await expect(exampleEditor).toHaveAttribute('data-ide-id', "2") + await expect(exampleEditor).toHaveAttribute('data-mode-id', "json") + await expect(exampleEditor).toHaveClass("editor active") + + const AASView = page.locator('#aas-view') + const consoleError = page.locator('#console-error') + const AASTab = page.locator("#aas-tab") + + await expect(AASView).toHaveClass("console-view aas-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(AASTab).toBeChecked({ checked: false }) + + await AASTab.click() + + await expect(AASTab).toBeChecked({ checked: true }) + await expect(AASView).toHaveClass("console-view aas-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const ASSEditor = page.locator('#aas-container') + const ASSContainer = ASSEditor.getByRole('code').locator('div').filter({ hasText: '"idShort": "AssetInterfacesDescription",' }).nth(4) + + await expect(ASSEditor).toHaveAttribute('data-mode-id', "json") + await expect(ASSContainer).toHaveText('"idShort": "AssetInterfacesDescription",') + + // Start waiting for download before clicking. + const AASDownload = page.locator('#aas-download') + const downloadPromise = page.waitForEvent('download') + await AASDownload.click() + const download = await downloadPromise + const expectedFilename = 'MyLampThing-AAS.json' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) +}) + +test.describe("Defaults view functionality", () => { + test("Opening the Defaults view with the Thing Template and closing it", async ({ page }) => { + + const initialTab = page.locator("#tab").nth(0) + await expect(initialTab).toHaveAttribute('data-tab-id', "1") + await expect(initialTab).toHaveText("TDThing TemplateCloseCancel") + await expect(initialTab).toHaveClass("active") + + const DefaultsView = page.locator('#defaults-view') + const consoleError = page.locator('#console-error') + const DefaultsTab = page.locator("#defaults-tab") + + await expect(DefaultsView).toHaveClass("console-view defaults-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(DefaultsTab).toBeChecked({ checked: false }) + + await DefaultsTab.click() + + await expect(DefaultsTab).toBeChecked({ checked: true }) + await expect(DefaultsView).toHaveClass("console-view defaults-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const defaultsEditor = page.locator('#defaults-container') + const defaultsContainer = defaultsEditor.getByRole('code').locator('div').filter({ hasText: '"description": "This is your customizable template. Edit it to fit your Thing Description or Thing Model needs!",' }).nth(4) + + await expect(defaultsEditor).toHaveAttribute('data-mode-id', "json") + await expect(defaultsContainer).toHaveText('"description": "This is your customizable template. Edit it to fit your Thing Description or Thing Model needs!",') + + const defaultsJsonBtn = page.locator('#defaults-json') + const defaultsAddBtn = page.locator('#defaults-add') + + await expect(defaultsJsonBtn).toBeDisabled() + await expect(defaultsAddBtn).toBeDisabled() + + const trashBtn = page.locator(".trash") + await trashBtn.click() + + await expect(DefaultsView).toHaveClass("console-view defaults-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(DefaultsTab).toBeChecked({ checked: false }) + }) + + test("Trying to open the Defaults view with a TM", async ({ page }) => { + + await page.locator("#examples-btn").click() + + const thingTypeToggle = page.locator('#thing-type-btn') + await thingTypeToggle.click() + await expect(thingTypeToggle).toBeChecked({ checked: true }) + + const quickAccessBtn = page.locator(".example").filter({ hasText: 'Basic TM' }).nth(1).getByRole("button").nth(0) + await quickAccessBtn.click() + + const exampleTab = page.locator("#tab").nth(1) + await expect(exampleTab).toHaveAttribute('data-tab-id', "2") + await expect(exampleTab).toHaveText("TMLamp ThingCloseCancel") + await expect(exampleTab).toHaveClass("active") + + const DefaultsView = page.locator('#defaults-view') + const consoleError = page.locator('#console-error') + const DefaultsTab = page.locator("#defaults-tab") + + await expect(DefaultsView).toHaveClass("console-view defaults-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(DefaultsTab).toBeChecked({ checked: false }) + + await DefaultsTab.click() + + await expect(DefaultsTab).toBeChecked({ checked: true }) + await expect(DefaultsView).toHaveClass("console-view defaults-view hidden") + await expect(page.locator(".console-error__txt")).toHaveText("This function is only allowed for Thing Descriptions!") + + }) + + test("Open the Defaults view as YAML", async ({ page }) => { + + const templateEditor = page.locator("#editor1") + await expect(templateEditor).toHaveAttribute('data-ide-id', "1") + await expect(templateEditor).toHaveAttribute('data-mode-id', "json") + await expect(templateEditor).toHaveClass("editor active") + + const jsonYamlPopup = page.locator('.json-yaml-warning') + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning closed") + + const jsonBtn = page.locator('#file-type-json') + const yamlBtn = page.locator('#file-type-yaml') + + await expect(jsonBtn).toBeChecked({ checked: true }) + await expect(yamlBtn).toBeChecked({ checked: false }) + + await yamlBtn.click() + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning") + + await page.locator('#yaml-confirm-btn').click() + await expect(jsonYamlPopup).toHaveClass("json-yaml-warning closed") + await expect(templateEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(jsonBtn).toBeChecked({ checked: false }) + await expect(yamlBtn).toBeChecked({ checked: true }) + + const defaultsView = page.locator('#defaults-view') + const consoleError = page.locator('#console-error') + const defaultsTab = page.locator("#defaults-tab") + + await expect(defaultsView).toHaveClass("console-view defaults-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(defaultsTab).toBeChecked({ checked: false }) + + await defaultsTab.click() + + await expect(defaultsTab).toBeChecked({ checked: true }) + await expect(defaultsView).toHaveClass("console-view defaults-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const defaultsEditor = page.locator('#defaults-container') + const defaultsContainer = defaultsEditor.getByRole('code').locator('div').filter({ hasText: 'description: >-' }).nth(4) + await expect(defaultsEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(defaultsContainer).toHaveText('description: >-') + + const defaultsYamlBtn = page.locator('#defaults-yaml') + await expect(defaultsYamlBtn).toBeDisabled() + }) + + test("Open the Defaults view and change form JSON to YAML and from YAML to JSON", async ({ page }) => { + const templateEditor = page.locator("#editor1") + await expect(templateEditor).toHaveAttribute('data-ide-id', "1") + await expect(templateEditor).toHaveAttribute('data-mode-id', "json") + await expect(templateEditor).toHaveClass("editor active") + + const defaultsView = page.locator('#defaults-view') + const consoleError = page.locator('#console-error') + const defaultsTab = page.locator("#defaults-tab") + + await expect(defaultsView).toHaveClass("console-view defaults-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(defaultsTab).toBeChecked({ checked: false }) + + await defaultsTab.click() + + await expect(defaultsTab).toBeChecked({ checked: true }) + await expect(defaultsView).toHaveClass("console-view defaults-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const defaultsEditor = page.locator('#defaults-container') + + await expect(defaultsEditor).toHaveAttribute('data-mode-id', "json") + + const defaultsJsonBtn = page.locator('#defaults-json') + const defaultsYamlBtn = page.locator('#defaults-yaml') + + await expect(defaultsJsonBtn).toBeDisabled() + + await defaultsYamlBtn.click() + + await expect(defaultsEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(defaultsYamlBtn).toBeDisabled() + + await defaultsJsonBtn.click() + + await expect(defaultsEditor).toHaveAttribute('data-mode-id', "json") + await expect(defaultsJsonBtn).toBeDisabled() + }) + + test("Open the Defaults view and removing and adding default values", async ({ page }) => { + + const templateEditor = page.locator("#editor1") + await expect(templateEditor).toHaveAttribute('data-ide-id', "1") + await expect(templateEditor).toHaveClass("editor active") + + const defaultsView = page.locator('#defaults-view') + const consoleError = page.locator('#console-error') + const defaultsTab = page.locator("#defaults-tab") + + await expect(defaultsView).toHaveClass("console-view defaults-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(defaultsTab).toBeChecked({ checked: false }) + + await defaultsTab.click() + + await expect(defaultsTab).toBeChecked({ checked: true }) + await expect(defaultsView).toHaveClass("console-view defaults-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const defaultsAddBtn = page.locator('#defaults-add') + const defaultsRemoveBtn = page.locator('#defaults-remove') + + await expect(defaultsAddBtn).toBeDisabled() + + await defaultsRemoveBtn.click() + await expect(defaultsRemoveBtn).toBeDisabled() + + await defaultsAddBtn.click() + await expect(defaultsAddBtn).toBeDisabled() + }) + + test("Open the Defaults view and downloading it as JSON with defaults", async ({ page }) => { + + const templateEditor = page.locator("#editor1") + await expect(templateEditor).toHaveAttribute('data-ide-id', "1") + await expect(templateEditor).toHaveAttribute('data-mode-id', "json") + await expect(templateEditor).toHaveClass("editor active") + + const DefaultsView = page.locator('#defaults-view') + const consoleError = page.locator('#console-error') + const DefaultsTab = page.locator("#defaults-tab") + + await expect(DefaultsView).toHaveClass("console-view defaults-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(DefaultsTab).toBeChecked({ checked: false }) + + await DefaultsTab.click() + + await expect(DefaultsTab).toBeChecked({ checked: true }) + await expect(DefaultsView).toHaveClass("console-view defaults-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const defaultsEditor = page.locator('#defaults-container') + await expect(defaultsEditor).toHaveAttribute('data-mode-id', "json") + + const DefaultsJsonBtn = page.locator('#defaults-json') + await expect(DefaultsJsonBtn).toBeDisabled() + + // Start waiting for download before clicking. + const DefaultsDownload = page.locator('#defaults-download') + const downloadPromise = page.waitForEvent('download') + await DefaultsDownload.click() + const download = await downloadPromise + const expectedFilename = 'Thing-Template-with-Defaults.json' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) + + test("Open the OpenAPI view and downloading it as YAML", async ({ page }) => { + const templateEditor = page.locator("#editor1") + await expect(templateEditor).toHaveAttribute('data-ide-id', "1") + await expect(templateEditor).toHaveAttribute('data-mode-id', "json") + await expect(templateEditor).toHaveClass("editor active") + + const DefaultsView = page.locator('#defaults-view') + const consoleError = page.locator('#console-error') + const DefaultsTab = page.locator("#defaults-tab") + + await expect(DefaultsView).toHaveClass("console-view defaults-view hidden") + await expect(consoleError).toHaveClass("console-view console-error hidden") + await expect(DefaultsTab).toBeChecked({ checked: false }) + + await DefaultsTab.click() + + await expect(DefaultsTab).toBeChecked({ checked: true }) + await expect(DefaultsView).toHaveClass("console-view defaults-view") + await expect(consoleError).toHaveClass("console-view console-error hidden") + + const defaultsEditor = page.locator('#defaults-container') + await expect(defaultsEditor).toHaveAttribute('data-mode-id', "json") + + const defaultsJsonBtn = page.locator('#defaults-json') + const defaultsYamlBtn = page.locator('#defaults-yaml') + + await expect(defaultsJsonBtn).toBeDisabled() + + await defaultsYamlBtn.click() + + await expect(defaultsEditor).toHaveAttribute('data-mode-id', "yaml") + await expect(defaultsYamlBtn).toBeDisabled() + + const defaultsAddBtn = page.locator('#defaults-add') + const defaultsRemoveBtn = page.locator('#defaults-remove') + + await expect(defaultsAddBtn).toBeDisabled() + + await defaultsRemoveBtn.click() + await expect(defaultsRemoveBtn).toBeDisabled() + + // Start waiting for download before clicking. + const defaultsDownload = page.locator('#defaults-download') + const downloadPromise = page.waitForEvent('download') + await defaultsDownload.click() + const download = await downloadPromise + const expectedFilename = 'Thing-Template-without-Defaults.yaml' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) +}) + +test.describe("Visualization view functionality", () => { + + test("Open the visualization view with the thing template and closing it", async ({ page }) => { + + const visualizeView = page.locator('#visualize-view') + const visualizeTab = page.locator("#visualize-tab") + + await expect(visualizeView).toHaveClass("console-view visualize-view hidden") + await expect(visualizeTab).toBeChecked({ checked: false }) + + await visualizeTab.click() + + await expect(visualizeTab).toBeChecked({ checked: true }) + await expect(visualizeView).toHaveClass("console-view visualize-view") + + const graphViewBtn = page.locator('#graph-view') + const treeViewBtn = page.locator('#tree-view') + + await expect(graphViewBtn).toBeChecked({ checked: true }) + await expect(treeViewBtn).toBeChecked({ checked: false }) + + const graphVisTitle = page.locator('#visualized').getByText('Thing Template', { exact: true }) + await expect(graphVisTitle).toHaveText("Thing Template") + + const trashBtn = page.locator(".trash") + await trashBtn.click() + + await expect(visualizeView).toHaveClass("console-view visualize-view hidden") + await expect(visualizeTab).toBeChecked({ checked: false }) + }) + + test("Open the visualization view with the thing template and expand and collapse the graph view", async ({ page }) => { + + const visualizeView = page.locator('#visualize-view') + const visualizeTab = page.locator("#visualize-tab") + + await expect(visualizeView).toHaveClass("console-view visualize-view hidden") + await expect(visualizeTab).toBeChecked({ checked: false }) + + await visualizeTab.click() + + await expect(visualizeTab).toBeChecked({ checked: true }) + await expect(visualizeView).toHaveClass("console-view visualize-view") + + const graphViewBtn = page.locator('#graph-view') + const treeViewBtn = page.locator('#tree-view') + const collapseAllBtn = page.locator('#collapse-all') + const expandAllBtn = page.locator('#expand-all') + + await expect(graphViewBtn).toBeChecked({ checked: true }) + await expect(treeViewBtn).toBeChecked({ checked: false }) + + const svgPaths = page.locator("svg > g > path") + await expect(svgPaths).toHaveCount(9) + + await expandAllBtn.click() + await expect(expandAllBtn).toBeDisabled() + + await expect(svgPaths).toHaveCount(12) + + await collapseAllBtn.click() + await expect(collapseAllBtn).toBeDisabled() + + await expect(svgPaths).toHaveCount(0) + }) + + test("Open the visualization view with the thing template download the graph view as SVG", async ({ page }) => { + + const visualizeView = page.locator('#visualize-view') + const visualizeTab = page.locator("#visualize-tab") + + await expect(visualizeView).toHaveClass("console-view visualize-view hidden") + await expect(visualizeTab).toBeChecked({ checked: false }) + + await visualizeTab.click() + + await expect(visualizeTab).toBeChecked({ checked: true }) + await expect(visualizeView).toHaveClass("console-view visualize-view") + + const graphViewBtn = page.locator('#graph-view') + const treeViewBtn = page.locator('#tree-view') + + await expect(graphViewBtn).toBeChecked({ checked: true }) + await expect(treeViewBtn).toBeChecked({ checked: false }) + + // Start waiting for download before clicking. + const svgDownload = page.locator('#download-svg') + const downloadPromise = page.waitForEvent('download') + await svgDownload.click() + const download = await downloadPromise + const expectedFilename = 'Graph-visualization.svg' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) + + test("Open the visualization view with the thing template and download the graph view as PNG", async ({ page }) => { + + const visualizeView = page.locator('#visualize-view') + const visualizeTab = page.locator("#visualize-tab") + + await expect(visualizeView).toHaveClass("console-view visualize-view hidden") + await expect(visualizeTab).toBeChecked({ checked: false }) + + await visualizeTab.click() + + await expect(visualizeTab).toBeChecked({ checked: true }) + await expect(visualizeView).toHaveClass("console-view visualize-view") + + const graphViewBtn = page.locator('#graph-view') + const treeViewBtn = page.locator('#tree-view') + + await expect(graphViewBtn).toBeChecked({ checked: true }) + await expect(treeViewBtn).toBeChecked({ checked: false }) + + // Start waiting for download before clicking. + const pngDownload = page.locator('#download-png') + const downloadPromise = page.waitForEvent('download') + await pngDownload.click() + const download = await downloadPromise + const expectedFilename = 'Graph-visualization.png' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) + + test("Open the tree visualization view with the thing template and modified the input values", async ({ page }) => { + + const visualizeView = page.locator('#visualize-view') + const visualizeTab = page.locator("#visualize-tab") + + await expect(visualizeView).toHaveClass("console-view visualize-view hidden") + await expect(visualizeTab).toBeChecked({ checked: false }) + + await visualizeTab.click() + + await expect(visualizeTab).toBeChecked({ checked: true }) + await expect(visualizeView).toHaveClass("console-view visualize-view") + + const graphViewBtn = page.locator('#graph-view') + const treeViewBtn = page.locator('#tree-view') + + await expect(graphViewBtn).toBeChecked({ checked: true }) + await expect(treeViewBtn).toBeChecked({ checked: false }) + + await treeViewBtn.click() + await expect(graphViewBtn).toBeChecked({ checked: false }) + await expect(treeViewBtn).toBeChecked({ checked: true }) + + const labelBtn = page.getByLabel('labels') + const radiusSlider = page.getByLabel('radius') + const extentSlider = page.getByLabel('extent') + const rotateSlider = page.getByLabel('rotate') + const dragSlider = page.getByLabel('drag precision') + const tidyBtn = page.getByLabel('tidy') + const clusterBtn = page.getByLabel('cluster') + const linksDropDown = page.getByLabel('links') + + await expect(labelBtn).toBeChecked({ checked: true }) + await expect(radiusSlider).toHaveValue("350") + await expect(extentSlider).toHaveValue("360") + await expect(rotateSlider).toHaveValue("0") + await expect(dragSlider).toHaveValue("100") + await expect(tidyBtn).toBeChecked({ checked: true }) + await expect(clusterBtn).toBeChecked({ checked: false }) + await expect(linksDropDown).toHaveValue("line") + + await labelBtn.click() + await radiusSlider.click() + await extentSlider.click() + await rotateSlider.click() + await dragSlider.click() + await clusterBtn.check() + await linksDropDown.selectOption("diagonal") + await expect(labelBtn).toBeChecked({ checked: false }) + + const radiusSliderValue = await radiusSlider.inputValue() + expect(parseInt(radiusSliderValue)).toBeLessThan(450) + expect(parseInt(radiusSliderValue)).toBeGreaterThan(330) + + const extentSliderValue = await extentSlider.inputValue() + expect(parseInt(extentSliderValue)).toBeLessThan(190) + expect(parseInt(extentSliderValue)).toBeGreaterThan(170) + + const rotateSliderValue = await rotateSlider.inputValue() + expect(parseInt(rotateSliderValue)).toBeLessThan(190) + expect(parseInt(rotateSliderValue)).toBeGreaterThan(170) + + const dragSliderValue = await dragSlider.inputValue() + expect(parseInt(dragSliderValue)).toBeLessThan(60) + expect(parseInt(dragSliderValue)).toBeGreaterThan(40) + + await expect(tidyBtn).toBeChecked({ checked: false }) + await expect(clusterBtn).toBeChecked({ checked: true }) + await expect(linksDropDown).toHaveValue("diagonal") + + }) + + test("Open the tree visualization view with the thing template and download as SVG", async ({ page }) => { + + const visualizeView = page.locator('#visualize-view') + const visualizeTab = page.locator("#visualize-tab") + + await expect(visualizeView).toHaveClass("console-view visualize-view hidden") + await expect(visualizeTab).toBeChecked({ checked: false }) + + await visualizeTab.click() + + await expect(visualizeTab).toBeChecked({ checked: true }) + await expect(visualizeView).toHaveClass("console-view visualize-view") + + const graphViewBtn = page.locator('#graph-view') + const treeViewBtn = page.locator('#tree-view') + + await expect(graphViewBtn).toBeChecked({ checked: true }) + await expect(treeViewBtn).toBeChecked({ checked: false }) + + await treeViewBtn.click() + await expect(graphViewBtn).toBeChecked({ checked: false }) + await expect(treeViewBtn).toBeChecked({ checked: true }) + + // Start waiting for download before clicking. + const svgDownload = page.locator('#download-svg') + const downloadPromise = page.waitForEvent('download') + await svgDownload.click() + const download = await downloadPromise + const expectedFilename = 'Tree-visualization.svg' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) + + test("Open the tree visualization view with the thing template and download as PNG", async ({ page }) => { + + const visualizeView = page.locator('#visualize-view') + const visualizeTab = page.locator("#visualize-tab") + + await expect(visualizeView).toHaveClass("console-view visualize-view hidden") + await expect(visualizeTab).toBeChecked({ checked: false }) + + await visualizeTab.click() + + await expect(visualizeTab).toBeChecked({ checked: true }) + await expect(visualizeView).toHaveClass("console-view visualize-view") + + const graphViewBtn = page.locator('#graph-view') + const treeViewBtn = page.locator('#tree-view') + + await expect(graphViewBtn).toBeChecked({ checked: true }) + await expect(treeViewBtn).toBeChecked({ checked: false }) + + await treeViewBtn.click() + await expect(graphViewBtn).toBeChecked({ checked: false }) + await expect(treeViewBtn).toBeChecked({ checked: true }) + + // Start waiting for download before clicking. + const pngDownload = page.locator('#download-png') + const downloadPromise = page.waitForEvent('download') + await pngDownload.click() + const download = await downloadPromise + const expectedFilename = 'Tree-visualization.png' + expect(download.suggestedFilename()).toBe(expectedFilename) + }) +}) \ No newline at end of file