diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6745492ab..35dd04958 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,6 +76,45 @@ jobs: - run: npm ci - run: npm run test + e2e: + name: "e2e tests" + runs-on: ubuntu-latest + services: + perses: + image: persesdev/perses:v0.53.0-rc.1 + ports: ["8080:8080"] + env: + PERSES_PLUGIN_ENABLE_DEV: "true" + steps: + - name: checkout + uses: actions/checkout@v6 + - uses: perses/github-actions@v0.11.0 + - uses: ./.github/perses-ci/actions/setup_environment + with: + enable_npm: true + nvmrc_path: ".nvmrc" + - name: install dependencies + run: npm ci + - name: install percli + uses: perses/cli-actions/actions/install_percli@v0.2.0 + with: + cli-version: "v0.53.0-rc.1" + - name: verify percli installation + run: percli version + - name: install Playwright browsers + run: npx playwright install --with-deps + working-directory: e2e + - name: setup Perses and start Plugins + run: | + # Handshake with server on port 8080 + percli login http://localhost:8080 + PLUGINS=("table" "tracetable") + for plugin in "${PLUGINS[@]}"; do + percli plugin start "./$plugin" & + sleep 10 + npm run test:ci --prefix e2e -- "tests/$plugin" + done + type-check: name: "type-check" runs-on: ubuntu-latest diff --git a/e2e/.gitignore b/e2e/.gitignore new file mode 100644 index 000000000..335bd46df --- /dev/null +++ b/e2e/.gitignore @@ -0,0 +1,8 @@ + +# Playwright +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +/playwright/.auth/ diff --git a/e2e/package-lock.json b/e2e/package-lock.json new file mode 100644 index 000000000..ac2d5bcf0 --- /dev/null +++ b/e2e/package-lock.json @@ -0,0 +1,97 @@ +{ + "name": "e2e", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "e2e", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.58.2", + "@types/node": "^25.2.3" + } + }, + "node_modules/@playwright/test": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", + "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", + "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", + "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/e2e/package.json b/e2e/package.json new file mode 100644 index 000000000..178c25c7e --- /dev/null +++ b/e2e/package.json @@ -0,0 +1,16 @@ +{ + "name": "@perses-dev/plugins-e2e", + "version": "0.1.0", + "description": "e2e tests for plugins", + "private": true, + "scripts": { + "test:ci": "npx playwright test --workers=1 --reporter=github,list", + "test:install": "npx playwright install --with-deps", + "test:local": "npx playwright test --ui", + "build": "echo 'Skipping build for e2e tests'" + }, + "devDependencies": { + "@playwright/test": "^1.58.2", + "@types/node": "^25.2.3" + } +} diff --git a/e2e/playwright.config.ts b/e2e/playwright.config.ts new file mode 100644 index 000000000..ad6a6c1fe --- /dev/null +++ b/e2e/playwright.config.ts @@ -0,0 +1,40 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests', + fullyParallel: true, + retries: 0, + workers: 1, + reporter: 'list', + + use: { + baseURL: 'http://localhost:8080', + trace: 'off', + screenshot: 'only-on-failure', + video: 'off', + }, + + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + + expect: { + timeout: 10000, + }, +}); diff --git a/e2e/tests/table/table.spec.ts b/e2e/tests/table/table.spec.ts new file mode 100644 index 000000000..a54febd86 --- /dev/null +++ b/e2e/tests/table/table.spec.ts @@ -0,0 +1,21 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { test, expect } from '@playwright/test'; + +/* WAS ONLY ADDED FOR DEMONSTRATIONS*/ +test.describe('table Plugin', () => { + test('ONLY FOR PR DEMONSTRATION', async () => { + expect(true).toBeTruthy(); + }); +}); diff --git a/e2e/tests/tracetable/tracetable.spec.ts b/e2e/tests/tracetable/tracetable.spec.ts new file mode 100644 index 000000000..5275428cb --- /dev/null +++ b/e2e/tests/tracetable/tracetable.spec.ts @@ -0,0 +1,21 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { test, expect } from '@playwright/test'; + +/* WAS ONLY ADDED FOR DEMONSTRATIONS*/ +test.describe('tacetable Plugin', () => { + test('ONLY FOR PR DEMONSTRATION', async () => { + expect(true).toBeTruthy(); + }); +}); diff --git a/package-lock.json b/package-lock.json index 69bf86e96..44b13ce75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,8 @@ "timeseriestable", "tracetable", "tracingganttchart", - "victorialogs" + "victorialogs", + "e2e" ], "devDependencies": { "@module-federation/rsbuild-plugin": "^0.21.6", @@ -144,6 +145,14 @@ "use-resize-observer": "^9.0.0" } }, + "e2e": { + "name": "@perses-dev/plugins-e2e", + "version": "0.1.0", + "devDependencies": { + "@playwright/test": "^1.58.2", + "@types/node": "^25.2.3" + } + }, "flamechart": { "name": "@perses-dev/flame-chart-plugin", "version": "0.5.0-rc.1", @@ -3879,6 +3888,10 @@ "react-dom": "^17.0.2 || ^18.0.0" } }, + "node_modules/@perses-dev/plugins-e2e": { + "resolved": "e2e", + "link": true + }, "node_modules/@perses-dev/prometheus-plugin": { "resolved": "prometheus", "link": true @@ -3944,6 +3957,22 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@playwright/test": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", + "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -5156,13 +5185,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.13.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.13.tgz", - "integrity": "sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ==", + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", "devOptional": true, "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~7.16.0" } }, "node_modules/@types/parse-json": { @@ -13066,6 +13095,53 @@ "node": ">=8" } }, + "node_modules/playwright": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", + "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", + "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -15587,9 +15663,9 @@ } }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "devOptional": true, "license": "MIT" }, diff --git a/package.json b/package.json index 9df78a804..fe6890fd7 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "timeseriestable", "tracetable", "tracingganttchart", - "victorialogs" + "victorialogs", + "e2e" ], "peerDependencies": { "@types/react-dom": "^18.3.0", @@ -84,4 +85,4 @@ "typescript": "^5.4.2" }, "packageManager": "npm@10.9.2" -} \ No newline at end of file +} diff --git a/scripts/build-plugins/build-plugins.go b/scripts/build-plugins/build-plugins.go index 479b3a8b5..1338ff444 100644 --- a/scripts/build-plugins/build-plugins.go +++ b/scripts/build-plugins/build-plugins.go @@ -42,6 +42,9 @@ func main() { logrus.Info("no tag provided, building all plugins") for _, workspace := range workspaces { + if workspace == "e2e" { + continue + } logrus.Infof("Building plugin %s", workspace) pluginsToBuild = append(pluginsToBuild, async.Async(func() (string, error) { return workspace, command.Run("percli", "plugin", "build", fmt.Sprintf("--plugin.path=%s", workspace), "--skip.npm-install=true") diff --git a/scripts/golangci-lint/golangci-lint.go b/scripts/golangci-lint/golangci-lint.go index 38d54cbbc..96cbc9aea 100644 --- a/scripts/golangci-lint/golangci-lint.go +++ b/scripts/golangci-lint/golangci-lint.go @@ -16,6 +16,7 @@ package main import ( "os" "os/exec" + "path/filepath" "github.com/perses/perses/scripts/pkg/npm" "github.com/sirupsen/logrus" @@ -25,6 +26,12 @@ func main() { var isError bool for _, workspace := range npm.MustGetWorkspaces(".") { + + if filepath.Base(workspace) == "e2e" { + logrus.Infof("Skipping e2e workspace: %s", workspace) + continue + } + cmd := exec.Command("golangci-lint", "run") cmd.Dir = workspace cmd.Stdout = os.Stdout diff --git a/scripts/tidy-modules/tidy-modules.go b/scripts/tidy-modules/tidy-modules.go index 451907225..bcf76e58b 100644 --- a/scripts/tidy-modules/tidy-modules.go +++ b/scripts/tidy-modules/tidy-modules.go @@ -16,6 +16,7 @@ package main import ( "fmt" "os/exec" + "path/filepath" "github.com/perses/perses/scripts/pkg/npm" "github.com/sirupsen/logrus" @@ -42,6 +43,12 @@ func tidyGoModule(workspace string) error { func main() { for _, workspace := range npm.MustGetWorkspaces(".") { + + if filepath.Base(workspace) == "e2e" { + logrus.Infof("Skipping e2e workspace: %s", workspace) + continue + } + logrus.Infof("Tidying module in workspace %s..", workspace) if retrieveDepErr := tidyCueModule(workspace); retrieveDepErr != nil { logrus.WithError(retrieveDepErr).Fatalf("unable to resolve the module dependencies for plugin %s", workspace)