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