diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5e10090..8972c52 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -38,6 +38,45 @@ jobs: - run: npm ci - run: npm run compile-test - run: npm test + ui-test-scarb: + name: check scarb from different sources + strategy: + matrix: + from-config: [true, false] + from-path: [true, false] + from-asdf-local: [true, false] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "22.x" + cache: npm + # Scarb in PATH + - run: | + curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -v "2.9.1" + echo "PATH_SCARB_VERSION=2.9.1" >> $GITHUB_ENV + if: ${{ matrix.from-path }} + + # Scarb in config on ~/.local/bin/scarb + - run: | + curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -p -v "2.8.5" + echo "CONFIG_SCARB_VERSION=2.8.5" >> $GITHUB_ENV + if: ${{ matrix.from-config }} + + # Scarb from asdf + - uses: asdf-vm/actions/setup@v3 + if: ${{ matrix.from-asdf-local }} + - run: | + asdf plugin add scarb + asdf install scarb "2.9.2" + asdf local scarb "2.9.2" + echo "ASDF_SCARB_VERSION=2.9.2" >> $GITHUB_ENV + if: ${{ matrix.from-asdf-local }} + + - run: npm ci + - run: npm run compile-test + - run: xvfb-run --auto-servernum --server-args='-screen 0 1920x1080x24' npm run ui-test-scarb test-ui-parametrized: name: test ui strategy: @@ -63,10 +102,12 @@ jobs: if: ${{ matrix.os != 'ubuntu-latest'}} test-ui: if: ${{ always() }} - needs: test-ui-parametrized + needs: + - test-ui-parametrized + - ui-test-scarb runs-on: ubuntu-latest steps: - - if: needs.test-ui-parametrized.result == 'success' + - if: needs.test-ui-parametrized.result == 'success' && needs.ui-test-scarb.result == 'success' run: exit 0 - - if: needs.test-ui-parametrized.result != 'success' + - if: needs.test-ui-parametrized.result != 'success' || needs.ui-test-scarb.result != 'success' run: exit 1 diff --git a/package.json b/package.json index c4b66aa..4c55b43 100644 --- a/package.json +++ b/package.json @@ -174,7 +174,8 @@ "lint-eslint": "eslint .", "lint-fmt": "prettier --check .", "test": "node --test out/test/**/*.js", - "ui-test": "extest setup-and-run './out/ui-test/*.js' --code_version max --code_settings ui-test/settings.json --extensions_dir .test-extensions" + "ui-test-scarb": "extest setup-and-run './out/ui-test/scarb/*.js' --code_version max --code_settings ui-test/settings.json --extensions_dir .test-extensions", + "ui-test": "extest setup-and-run './out/ui-test/generic/*.js' --code_version max --code_settings ui-test/settings.json --extensions_dir .test-extensions" }, "engines": { "vscode": "^1.84.0" diff --git a/test-support/page-objects/cairoStatusBarItem.ts b/test-support/page-objects/cairoStatusBarItem.ts new file mode 100644 index 0000000..3ab1314 --- /dev/null +++ b/test-support/page-objects/cairoStatusBarItem.ts @@ -0,0 +1,22 @@ +import { StatusBar, WebElement } from "vscode-extension-tester"; + +export async function getStatusBarItem(): Promise { + const items = await new StatusBar().getItems(); + + for (const item of items) { + try { + // This can throw StaleElementReferenceError because item was destroyed before reading its text. + const text = await item.getText(); + + if (text.startsWith("Cairo")) { + return item; + } + } catch { + // No need to do anything here. + // If this was cairo status bar we will simply return after loop. + // Else it is not interesting for us anyway. + } + } + + return undefined; +} diff --git a/ui-test/expandMacro.ts b/ui-test/generic/expandMacro.ts similarity index 97% rename from ui-test/expandMacro.ts rename to ui-test/generic/expandMacro.ts index e0c43c6..5722928 100644 --- a/ui-test/expandMacro.ts +++ b/ui-test/generic/expandMacro.ts @@ -1,6 +1,6 @@ import { EditorView, TextEditor, VSBrowser, Workbench } from "vscode-extension-tester"; import { expect } from "chai"; -import { isScarbAvailable } from "../test-support/scarb"; +import { isScarbAvailable } from "../../test-support/scarb"; import * as path from "path"; describe("Expand macro test", function () { diff --git a/ui-test/statusBar.ts b/ui-test/generic/statusBar.ts similarity index 61% rename from ui-test/statusBar.ts rename to ui-test/generic/statusBar.ts index 419c4ba..32007aa 100644 --- a/ui-test/statusBar.ts +++ b/ui-test/generic/statusBar.ts @@ -1,7 +1,8 @@ -import { StatusBar, VSBrowser, WebElement, Workbench } from "vscode-extension-tester"; +import { StatusBar, VSBrowser, Workbench } from "vscode-extension-tester"; import { expect } from "chai"; -import { isScarbAvailable } from "../test-support/scarb"; +import { isScarbAvailable } from "../../test-support/scarb"; import * as path from "path"; +import { getStatusBarItem } from "../../test-support/page-objects/cairoStatusBarItem"; describe("Status bar", function () { this.timeout(50000); @@ -26,7 +27,7 @@ describe("Status bar", function () { if (isScarbAvailable) { expect(title).to.match( - /Cairo, (Cairo Language Server .+ \(.+\)\n)?Cairo Language\nscarb .+ \(.+\)\ncairo: .+ \(.+\)\nsierra: .+/, + /Cairo, (?:Cairo Language Server .+ \(.+\)\n)?Cairo Language\nscarb .+ \(.+\)\ncairo: .+ \(.+\)\nsierra: .+/, ); } else { expect(title).to.be.eq("Cairo, Cairo Language"); @@ -48,24 +49,3 @@ describe("Status bar", function () { expect(statusBarIsUndefined).to.be.true; }); }); - -async function getStatusBarItem(): Promise { - const items = await new StatusBar().getItems(); - - for (const item of items) { - try { - // This can throw StaleElementReferenceError because item was destroyed before reading its text. - const text = await item.getText(); - - if (text.startsWith("Cairo")) { - return item; - } - } catch { - // No need to do anything here. - // If this was cairo status bar we will simply return after loop. - // Else it is not interesting for us anyway. - } - } - - return undefined; -} diff --git a/ui-test/scarb/toolchain_info.ts b/ui-test/scarb/toolchain_info.ts new file mode 100644 index 0000000..f02a80b --- /dev/null +++ b/ui-test/scarb/toolchain_info.ts @@ -0,0 +1,74 @@ +import { StatusBar, VSBrowser, Workbench } from "vscode-extension-tester"; +import { expect } from "chai"; +import * as path from "path"; +import { getStatusBarItem } from "../../test-support/page-objects/cairoStatusBarItem"; +import { homedir } from "os"; + +describe("Toolchain info", function () { + this.timeout(50000); + + it("Checks correct scarb precedence", async function () { + // asdf is in fact in PATH and in our tests it is first scarb in path, special case this. + // It is caused by `@actions/core addPath` implementation. + // See: https://github.com/actions/toolkit/blob/01f21badd5a7522507f84558503b56c4deec5326/packages/core/src/core.ts#L107 + if (process.env.PATH_SCARB_VERSION && process.env.ASDF_SCARB_VERSION) { + process.env.PATH_SCARB_VERSION = process.env.ASDF_SCARB_VERSION; + } + + const scarbs = [ + // Order is important here. + process.env.CONFIG_SCARB_VERSION, + process.env.PATH_SCARB_VERSION, + process.env.ASDF_SCARB_VERSION, + ]; + + const expectedScarbVersion = scarbs.find(Boolean); // Find first with value. + + // Ignore this test locally, it is strictly designed for our CI. + if (!expectedScarbVersion) { + this.skip(); + } + + if (process.env.CONFIG_SCARB_VERSION) { + const workbench = new Workbench(); + + const settings = await workbench.openSettings(); + + const setting = await settings.findSetting("Scarb Path", "Cairo1"); + + setting.setValue(path.join(homedir(), ".local", "bin", "scarb")); + + await workbench.executeCommand("Cairo: Reload workspace"); + } + + await VSBrowser.instance.openResources(path.join("ui-test", "fixtures", "empty")); + + const statusBar = await VSBrowser.instance.driver.wait(getStatusBarItem, 5000); + + expect(statusBar).to.not.be.undefined; + + const title = await statusBar!.getAttribute(StatusBar["locators"].StatusBar.itemTitle); + + const matches = + /Cairo, (?:Cairo Language Server .+ \(.+\)\n)?Cairo Language\nscarb (.+) \(.+\)\ncairo: .+ \(.+\)\nsierra: .+/.exec( + title, + ); + + expect(matches).to.not.be.undefined; + + const scarbVersion = matches![1]; + + expect(scarbVersion).to.be.eq(expectedScarbVersion); + }); +}); + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace NodeJS { + interface ProcessEnv { + ASDF_SCARB_VERSION?: string; + CONFIG_SCARB_VERSION?: string; + PATH_SCARB_VERSION?: string; + } + } +}