From 4d14270da976adf48869a3a2b430275b8d18ca3c Mon Sep 17 00:00:00 2001 From: Ron <45816308+rjaegers@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:20:31 +0000 Subject: [PATCH 1/7] chore: consolidate formatting in amp-devcontainer-cpp --- .../cpp/devcontainer-metadata-vscode.json | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.devcontainer/cpp/devcontainer-metadata-vscode.json b/.devcontainer/cpp/devcontainer-metadata-vscode.json index e7264114..b4e6abff 100644 --- a/.devcontainer/cpp/devcontainer-metadata-vscode.json +++ b/.devcontainer/cpp/devcontainer-metadata-vscode.json @@ -12,12 +12,10 @@ "ms-vscode.cmake-tools@1.19.52", "ms-vscode.cpptools@1.21.6", "ms-vsliveshare.vsliveshare@1.0.5940", - "sonarsource.sonarlint-vscode@4.10.0", - "xaver.clang-format@1.9.0" + "sonarsource.sonarlint-vscode@4.10.0" ], "settings": { "C_Cpp.intelliSenseEngine": "disabled", - "C_Cpp.formatting": "clangFormat", "clangd.arguments": [ "--query-driver=/opt/**/arm-none-eabi-*", "--compile-commands-dir=${userHome}/.amp" @@ -25,7 +23,15 @@ "cmake.copyCompileCommands": "${userHome}/.amp/compile_commands.json", "cortex-debug.gdbPath": "gdb-multiarch", "cortex-debug.objdumpPath": "arm-none-eabi-objdump", - "sonarlint.pathToCompileCommands": "/root/.amp/compile_commands.json" + "sonarlint.pathToCompileCommands": "/root/.amp/compile_commands.json", + "[c]": { + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd", + "editor.formatOnSave": true + }, + "[cpp]": { + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd", + "editor.formatOnSave": true + } } } } From c794fd6d66dbbd785a79f3f6f472eb48e9301f32 Mon Sep 17 00:00:00 2001 From: Ron <45816308+rjaegers@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:00:50 +0000 Subject: [PATCH 2/7] chore: don't forcefully enable formatOnSave --- .devcontainer/cpp/devcontainer-metadata-vscode.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.devcontainer/cpp/devcontainer-metadata-vscode.json b/.devcontainer/cpp/devcontainer-metadata-vscode.json index b4e6abff..89f5fccf 100644 --- a/.devcontainer/cpp/devcontainer-metadata-vscode.json +++ b/.devcontainer/cpp/devcontainer-metadata-vscode.json @@ -25,12 +25,10 @@ "cortex-debug.objdumpPath": "arm-none-eabi-objdump", "sonarlint.pathToCompileCommands": "/root/.amp/compile_commands.json", "[c]": { - "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd", - "editor.formatOnSave": true + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" }, "[cpp]": { - "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd", - "editor.formatOnSave": true + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" } } } From 3d02d31cb3c39720a98ab53dfa5ef24029fdc17b Mon Sep 17 00:00:00 2001 From: Ron <45816308+rjaegers@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:19:26 +0000 Subject: [PATCH 3/7] chore: fix xwin-cache --- .github/workflows/ci.yml | 2 ++ .github/workflows/prime-cache.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1dab2204..e7465608 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,8 @@ jobs: with: path: test/.xwin-cache key: xwin-cache + restore-keys: | + xwin-cache - name: Run Tests run: | set -Eeuo pipefail diff --git a/.github/workflows/prime-cache.yml b/.github/workflows/prime-cache.yml index ae945914..4f14e062 100644 --- a/.github/workflows/prime-cache.yml +++ b/.github/workflows/prime-cache.yml @@ -52,4 +52,4 @@ jobs: - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: test/.xwin-cache - key: xwin-cache + key: xwin-cache-${{ github.run_id }} From 86699630a6c4feacea6d701f3053d5d4c0152aa1 Mon Sep 17 00:00:00 2001 From: Ron <45816308+rjaegers@users.noreply.github.com> Date: Fri, 27 Sep 2024 06:45:42 +0000 Subject: [PATCH 4/7] test: add test for formatting --- .../cpp/e2e/features/pages/codespace.pom.ts | 22 ++ .../features/static-dynamic-analysis.feature | 12 + .../cpp/e2e/features/steps/codespace.steps.ts | 44 +++ .../e2e/features/steps/compilation.steps.ts | 15 - .devcontainer/cpp/e2e/workspace/formatted.cpp | 7 + .../cpp/e2e/workspace/unformatted.cpp | 8 + package-lock.json | 268 +++++++++++++++++- package.json | 8 +- 8 files changed, 365 insertions(+), 19 deletions(-) create mode 100644 .devcontainer/cpp/e2e/features/static-dynamic-analysis.feature create mode 100644 .devcontainer/cpp/e2e/features/steps/codespace.steps.ts delete mode 100644 .devcontainer/cpp/e2e/features/steps/compilation.steps.ts create mode 100644 .devcontainer/cpp/e2e/workspace/formatted.cpp create mode 100644 .devcontainer/cpp/e2e/workspace/unformatted.cpp diff --git a/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts b/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts index 7fd4b9c4..dec60f96 100644 --- a/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts +++ b/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts @@ -101,7 +101,29 @@ export class CodespacePage { await expect(this.page.locator('[id="workbench.parts.editor"]')).toContainText(name); } + async openCppFileInEditor(name: string) { + await this.openFileInEditor(name); + await expect(this.page.locator('[id="llvm-vs-code-extensions.vscode-clangd"]')).toContainText('clangd: idle', { timeout: 1 * 60 * 1000 }); + } + + async formatDocument() { + await this.executeFromCommandPalette({ command: 'Format Document' }); + } + + async saveDocument() { + await this.page.keyboard.press('Control+S'); + } + async buildSelectedTarget() { await this.page.getByRole('button', { name: 'Build the selected target' }).click(); } + + async expectEditorContent(expected: RegExp) { + await expect(this.page.getByRole('code')).toContainText(expected); + } + + async expectFileContentsToMatch(actual: string, expected: string) { + await this.executeInTerminal(`diff -s ${actual} ${expected}`); + await expect(this.outputPanel).toContainText(`Files ${actual} and ${expected} are identical`); + } } diff --git a/.devcontainer/cpp/e2e/features/static-dynamic-analysis.feature b/.devcontainer/cpp/e2e/features/static-dynamic-analysis.feature new file mode 100644 index 00000000..9e3de367 --- /dev/null +++ b/.devcontainer/cpp/e2e/features/static-dynamic-analysis.feature @@ -0,0 +1,12 @@ +Feature: Analyze source code using static and dynamic analysis + + As a software craftsman + To maintain consistent, high-quality and bug-free code + Source code needs to be statically and dynamically analyzed + + Scenario: Format source code according to a formatting style + + Given the file "unformatted.cpp" is opened in the editor + When the active document is formatted + And the active document is saved + Then the contents of "unformatted.cpp" should match the contents of "formatted.cpp" diff --git a/.devcontainer/cpp/e2e/features/steps/codespace.steps.ts b/.devcontainer/cpp/e2e/features/steps/codespace.steps.ts new file mode 100644 index 00000000..110b8f80 --- /dev/null +++ b/.devcontainer/cpp/e2e/features/steps/codespace.steps.ts @@ -0,0 +1,44 @@ +import { expect } from "@playwright/test"; +import { Given, When, Then } from "./fixtures"; +import * as path from 'path'; + +Given("the default build configuration is selected", async () => { + // No-op +}); + +Given("the file {string} is opened in the editor", async ({ codespacePage }, file: string) => { + const fileExtension = path.extname(file).slice(1); + + switch (fileExtension) { + case 'cpp': + await codespacePage.openCppFileInEditor(file); + break; + default: + await codespacePage.openFileInEditor(file); + } +}); + +When("the configuration {string} is built", async ({ codespacePage }, configuration: string) => { + await codespacePage.page.getByRole('button', { name: 'Build the selected target' }).click(); + await codespacePage.page.getByLabel(configuration).locator('a').click(); +}); + +When("the active document is formatted", async ({ codespacePage }) => { + await codespacePage.formatDocument(); +}); + +When("the active document is saved", async ({ codespacePage }) => { + await codespacePage.saveDocument(); +}); + +Then("the output should contain {string}", async ({ codespacePage }, expectedOutput: string) => { + await expect(codespacePage.outputPanel).toContainText(expectedOutput, { timeout: 5 * 60 * 1000 }); +}); + +Then("the editor should contain {string}", async ({ codespacePage }, expectedContent: string) => { + await codespacePage.expectEditorContent(new RegExp(expectedContent)); +}); + +Then("the contents of {string} should match the contents of {string}", async ({ codespacePage }, actual: string, expected: string) => { + await codespacePage.expectFileContentsToMatch(actual, expected); +}); diff --git a/.devcontainer/cpp/e2e/features/steps/compilation.steps.ts b/.devcontainer/cpp/e2e/features/steps/compilation.steps.ts deleted file mode 100644 index 46afe7e0..00000000 --- a/.devcontainer/cpp/e2e/features/steps/compilation.steps.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { expect } from "@playwright/test"; -import { Given, When, Then } from "./fixtures"; - -Given("the default build configuration is selected", async () => { - // No-op -}); - -When("the configuration {string} is built", async ({ codespacePage }, configuration: string) => { - await codespacePage.page.getByRole('button', { name: 'Build the selected target' }).click(); - await codespacePage.page.getByLabel(configuration).locator('a').click(); -}); - -Then("the output should contain {string}", async ({ codespacePage }, expectedOutput: string) => { - await expect(codespacePage.outputPanel).toContainText(expectedOutput, { timeout: 5 * 60 * 1000 }); -}); diff --git a/.devcontainer/cpp/e2e/workspace/formatted.cpp b/.devcontainer/cpp/e2e/workspace/formatted.cpp new file mode 100644 index 00000000..c2266d56 --- /dev/null +++ b/.devcontainer/cpp/e2e/workspace/formatted.cpp @@ -0,0 +1,7 @@ +#include +#include + +int main() { + std::cout << "Hello World!" << std::endl; + return 0; +} diff --git a/.devcontainer/cpp/e2e/workspace/unformatted.cpp b/.devcontainer/cpp/e2e/workspace/unformatted.cpp new file mode 100644 index 00000000..faa6721a --- /dev/null +++ b/.devcontainer/cpp/e2e/workspace/unformatted.cpp @@ -0,0 +1,8 @@ +#include +#include + +int main() +{ + std::cout << "Hello World!" << std::endl; + return 0; +} diff --git a/package-lock.json b/package-lock.json index e04c7503..dcf474f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,19 @@ { - "name": "amp-devcontainer", + "name": "amp-devcontainer-tests", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "amp-devcontainer-tests", + "version": "1.0.0", "devDependencies": { "@playwright/test": "^1.47.2", "@types/node": "^22.5.5", "dotenv": "^16.4.5", + "nodemon": "^3.1.7", "otpauth": "^9.3.2", - "playwright-bdd": "7.2.2" + "playwright-bdd": "^7.2.2" } }, "node_modules/@colors/colors": { @@ -283,6 +287,51 @@ "node": ">=8" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -303,6 +352,31 @@ "dev": true, "license": "MIT" }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/class-transformer": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", @@ -336,6 +410,31 @@ "node": ">=18" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/dotenv": { "version": "16.4.5", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", @@ -422,6 +521,36 @@ "node": ">= 6" } }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -489,6 +618,65 @@ "node": ">=8.6" } }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", + "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/otpauth": { "version": "9.3.2", "resolved": "https://registry.npmjs.org/otpauth/-/otpauth-9.3.2.tgz", @@ -576,6 +764,13 @@ "node": ">=18" } }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -597,6 +792,19 @@ ], "license": "MIT" }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", @@ -659,6 +867,32 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -708,6 +942,19 @@ "node": ">=8" } }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -721,6 +968,23 @@ "node": ">=8.0" } }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", diff --git a/package.json b/package.json index 09cd3876..ae7b8bd4 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,14 @@ "@playwright/test": "^1.47.2", "@types/node": "^22.5.5", "dotenv": "^16.4.5", + "nodemon": "^3.1.7", "otpauth": "^9.3.2", - "playwright-bdd": "7.2.2" + "playwright-bdd": "^7.2.2" }, "scripts": { - "test": "cd $INIT_CWD && npx bddgen && npx playwright test" + "test": "cd $INIT_CWD && npx bddgen && npx playwright test", + "watch:bdd-gen": "cd $INIT_CWD && nodemon -L -w features -w steps -w pages -e feature,ts -x 'npx bddgen'", + "watch:playwright": "cd $INIT_CWD && playwright test --ui", + "watch": "cd $INIT_CWD && npm run watch:bdd-gen & npm run watch:playwright" } } From 1cf5f3b552eb5ac3d87bf3e3fbb77e0194f91acc Mon Sep 17 00:00:00 2001 From: Ron <45816308+rjaegers@users.noreply.github.com> Date: Fri, 27 Sep 2024 07:46:35 +0000 Subject: [PATCH 5/7] test: make execute in terminal more robust --- .../cpp/e2e/features/pages/codespace.pom.ts | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts b/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts index dec60f96..5cc582bd 100644 --- a/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts +++ b/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts @@ -46,28 +46,6 @@ export class CodespacePage { await expect(this.page.getByRole('button', { name: 'Activating Extensions...' })).toBeHidden(); } - /** - * Executes the given commands in the terminal. - * - * **Usage** - * - * ```ts - * const codespace = new CodespacePage(page); - * await codespace.executeInTerminal('git clean -fdx'); - * ``` - * - * @param commands - The commands to execute in the terminal. It can be a single command or an array of commands. - */ - async executeInTerminal(commands: string | string[]) { - await this.page.keyboard.press('Control+Shift+`'); - await expect(this.page.locator('.terminal-wrapper.active')).toBeVisible(); - - for (const command of Array.isArray(commands) ? [...commands + 'exit'] : [commands, 'exit']) { - await this.terminal.pressSequentially(command); - await this.terminal.press('Enter'); - } - } - /** * Executes the given commands in the command palette. * @@ -82,11 +60,33 @@ export class CodespacePage { for (const command of Array.isArray(commands) ? commands : [commands]) { let prompt = this.page.getByPlaceholder(command.prompt || 'Type the name of a command to run'); - await prompt.pressSequentially(command.command); + await prompt.fill(`> ${command.command}`); await prompt.press('Enter'); } } + /** + * Executes the given commands in the terminal. + * + * **Usage** + * + * ```ts + * const codespace = new CodespacePage(page); + * await codespace.executeInTerminal('git clean -fdx'); + * ``` + * + * @param commands - The commands to execute in the terminal. It can be a single command or an array of commands. + */ + async executeInTerminal(commands: string | string[]) { + await this.executeFromCommandPalette({ command: 'Terminal: Focus on Terminal View' }); + await expect(this.page.locator('.terminal-widget-container')).toBeVisible(); + + for (const command of Array.isArray(commands) ? commands : [commands]) { + await this.terminal.fill(command); + await this.terminal.press('Enter'); + } + } + /** * Opens the tab with the given name. * From 5d8b9de19580fe13a94030739dce085c8ccdd2aa Mon Sep 17 00:00:00 2001 From: Ron <45816308+rjaegers@users.noreply.github.com> Date: Fri, 27 Sep 2024 08:02:02 +0000 Subject: [PATCH 6/7] test: revert fill on terminal; element is not an input --- .devcontainer/cpp/e2e/features/pages/codespace.pom.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts b/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts index 5cc582bd..d33f00c6 100644 --- a/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts +++ b/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts @@ -82,7 +82,7 @@ export class CodespacePage { await expect(this.page.locator('.terminal-widget-container')).toBeVisible(); for (const command of Array.isArray(commands) ? commands : [commands]) { - await this.terminal.fill(command); + await this.terminal.pressSequentially(command); await this.terminal.press('Enter'); } } From a1ecf51f49cae087e1d8005c2a1c624ca345e4f7 Mon Sep 17 00:00:00 2001 From: Ron <45816308+rjaegers@users.noreply.github.com> Date: Fri, 27 Sep 2024 08:22:45 +0000 Subject: [PATCH 7/7] test: look in the correct place for terminal output --- .devcontainer/cpp/e2e/features/pages/codespace.pom.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts b/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts index d33f00c6..b1061cd3 100644 --- a/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts +++ b/.devcontainer/cpp/e2e/features/pages/codespace.pom.ts @@ -124,6 +124,6 @@ export class CodespacePage { async expectFileContentsToMatch(actual: string, expected: string) { await this.executeInTerminal(`diff -s ${actual} ${expected}`); - await expect(this.outputPanel).toContainText(`Files ${actual} and ${expected} are identical`); + await expect(this.page.locator('#terminal')).toContainText(`Files ${actual} and ${expected} are identical`); } }