Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 57 additions & 116 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ jobs:
name: Setup outputs
run: ./.github/scripts/get_runner_classes.sh

workspace-tests:

e2e-tests:
needs: setup
runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }}
defaults:
run:
working-directory: ui
runs-on: ${{ fromJSON(needs.setup.outputs.compute-medium) }}
continue-on-error: true
env:
CONSUL_NSPACES_ENABLED: 0
steps:
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4

Expand All @@ -50,132 +51,74 @@ jobs:
cache: "pnpm"
cache-dependency-path: "ui/pnpm-lock.yaml"

# Install dependencies.
- name: install packages
- name: Install dependencies
working-directory: ui
run: make deps

- run: make test-workspace

node-tests:
needs: setup
runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }}
steps:
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4

- name: Install PNPM
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Checkout consul-ui-testing repo
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
run_install: false
package_json_file: ui/package.json

- name: Setup node and pnpm cache
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version-file: "./ui/package.json"
cache: "pnpm"
cache-dependency-path: "ui/pnpm-lock.yaml"

# Install dependencies.
- name: install packages
working-directory: ui
run: make deps

- run: make test-node
working-directory: ui/packages/consul-ui

ember-build-test:
needs: setup
if: ${{ !endsWith(github.repository, '-enterprise') }}
runs-on: ${{ fromJSON(needs.setup.outputs.compute-large ) }}
strategy:
matrix:
partition: [1, 2, 3, 4]
env:
EMBER_TEST_REPORT: test-results/report-ce.xml # outputs test report for CI test summary
EMBER_TEST_PARALLEL: true # enables test parallelization with ember-exam
CONSUL_NSPACES_ENABLED: 0 # NOTE: this should be 1 in ENT.
JOBS: 2 # limit parallelism for broccoli-babel-transpiler
steps:
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
repository: hashicorp/consul-ui-testing
path: consul-ui-testing
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}

- name: Install PNPM
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
with:
run_install: false
package_json_file: ui/package.json
- name: Install consul-ui-testing dependencies
working-directory: consul-ui-testing
run: yarn install

- name: Setup node and pnpm cache
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version-file: "./ui/package.json"
cache: "pnpm"
cache-dependency-path: "ui/pnpm-lock.yaml"
- name: Install httpie (required by consul-ui-testing)
run: |
sudo apt-get update
sudo apt-get install -y httpie

- name: Install Chrome
uses: browser-actions/setup-chrome@82b9ce628cc5595478a9ebadc480958a36457dc2 # v1.6.0
- name: Skip HashiCups build (use cached version marker)
working-directory: consul-ui-testing
run: echo "hashicorppreview/consul:latest" > .last_consul_version_built

- name: Install dependencies
working-directory: ui
run: make deps
- name: Start Consul API servers
working-directory: consul-ui-testing
run: |
echo "Starting Consul API servers at $(date '+%Y-%m-%d %H:%M:%S')"
yarn start hashicorppreview/consul:latest

- name: Build CI
- name: Start Consul UI
working-directory: ui/packages/consul-ui
run: make build-ci
run: |
pnpm run start:consul &
echo $! > consul-ui.pid
env:
CONSUL_HTTP_ADDR: http://localhost:8500

- name: Ember exam
working-directory: ui/packages/consul-ui
run: node_modules/.bin/ember exam --split=4 --partition=${{ matrix.partition }} --path dist --silent -r xunit
- name: Wait for UI to be ready
run: npx wait-on http://localhost:4200 --timeout 60000

- name: Test Coverage CI
- name: Run E2E health check
working-directory: ui/packages/consul-ui
run: make test-coverage-ci
run: pnpm run test:e2e:health

ember-build-test-ent:
needs: setup
runs-on: ${{ fromJSON(needs.setup.outputs.compute-large ) }}
strategy:
matrix:
partition: [1, 2, 3, 4]
env:
EMBER_TEST_REPORT: test-results/report-ce.xml # outputs test report for CI test summary
EMBER_TEST_PARALLEL: true # enables test parallelization with ember-exam
CONSUL_NSPACES_ENABLED: 1 # NOTE: this should be 1 in ENT.
JOBS: 2 # limit parallelism for broccoli-babel-transpiler
steps:
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4

- name: Install PNPM
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Run basic E2E tests
working-directory: ui/packages/consul-ui
run: pnpm run test:e2e:basic
env:
CI: true
CONSUL_UI_TEST_TOKEN: ${{ secrets.CONSUL_UI_TEST_TOKEN }}

- name: Upload test results
if: always()
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
run_install: false
package_json_file: ui/package.json
name: e2e-test-results-ce
path: ui/packages/consul-ui/e2e-tests/reports/
retention-days: 30

- name: Setup node and pnpm cache
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
- name: Upload screenshots on failure
if: failure()
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
node-version-file: "./ui/package.json"
cache: "pnpm"
cache-dependency-path: "ui/pnpm-lock.yaml"

- name: Install Chrome
uses: browser-actions/setup-chrome@82b9ce628cc5595478a9ebadc480958a36457dc2 # v1.6.0
name: e2e-screenshots-ce
path: ui/packages/consul-ui/e2e-tests/reports/test-results/
retention-days: 7

- name: Install dependencies
working-directory: ui
run: make deps

- name: Build CI
working-directory: ui/packages/consul-ui
run: make build-ci

- name: Ember exam
working-directory: ui/packages/consul-ui
run: node_modules/.bin/ember exam --split=4 --partition=${{ matrix.partition }} --path dist --silent -r xunit

- name: Test Coverage CI
working-directory: ui/packages/consul-ui
run: make test-coverage-ci
# This is job is required for branch protection as a required gihub check
# because GitHub actions show up as checks at the job level and not the
# workflow level. This is currently a feature request:
Expand All @@ -193,9 +136,7 @@ jobs:
frontend-success:
needs:
- setup
- workspace-tests
- node-tests
- ember-build-test
- e2e-tests
runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }}
if: ${{ always() }}
steps:
Expand Down
8 changes: 8 additions & 0 deletions ui/packages/consul-ui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,11 @@
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try


# Playwright E2E test artifacts
e2e-tests/reports/
e2e-tests/.auth/
.playwright/
e2e-tests/auth-state.json
playwright/.cache/
57 changes: 57 additions & 0 deletions ui/packages/consul-ui/e2e-tests/global-setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const { chromium } = require('@playwright/test');
const { checkAllServices, printServiceErrors } = require('./utils/health-check-utils');
const { loginWithToken } = require('./utils/auth-utils');

async function globalSetup(config) {
console.log('\n🚀 Starting E2E Test Setup...\n');

const baseURL = config.projects?.[0]?.use?.baseURL || 'http://localhost:4200';

console.log('🔍 Checking service health...\n');

const healthChecks = await checkAllServices(baseURL);

let allHealthy = true;
const failedServices = [];

healthChecks.forEach((s) => {
console.log(`${s.isHealthy ? '✅' : '❌'} ${s.name}: ${s.url}`);
if (!s.isHealthy) {
allHealthy = false;
failedServices.push(s);
}
});

if (!allHealthy) {
console.log('\n⚠️ Some services are not accessible. Tests may fail.\n');
printServiceErrors(failedServices);
}

// Perform authentication and save state
console.log('\n🔐 Authenticating to Consul UI...\n');

const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();

try {
// Login using the token from environment
await loginWithToken(page);

console.log('✅ Authentication successful.\n');

// Save the authenticated state for all tests to reuse
await context.storageState({ path: 'ui/packages/consul-ui/e2e-tests/auth-state.json' });

console.log('💾 Saved authentication state.\n');
} catch (error) {
console.error('❌ Authentication failed:', error.message);
throw error;
} finally {
await browser.close();
}

console.log('✅ Setup complete!\n');
}

module.exports = globalSetup;
22 changes: 22 additions & 0 deletions ui/packages/consul-ui/e2e-tests/global-teardown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Global Teardown for Playwright E2E Tests
*
* Runs once after all tests
* - Clean up resources
* - Archive logs if needed
*/

async function globalTeardown(config) {
console.log('\n🧹 Starting E2E Test Cleanup...\n');

// TODO: Add cleanup tasks
// - Clean up authentication state files
// - Archive logs if tests failed
// - Clean up any test data

console.log('✅ Cleanup complete!\n');
}

module.exports = globalTeardown;

// Made with Bob
35 changes: 35 additions & 0 deletions ui/packages/consul-ui/e2e-tests/health-check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env node
const { checkAllServices, printServiceErrors } = require('./utils/health-check-utils');

async function runHealthCheck() {
console.log('\n🏥 E2E Environment Health Check\n');

const healthChecks = await checkAllServices();

let allRequiredHealthy = true;
const failedServices = [];

healthChecks.forEach((s) => {
const status = s.isHealthy ? '✅' : '❌';
const label = s.required ? 'REQUIRED' : 'OPTIONAL';
console.log(`${status} [${label}] ${s.name}: ${s.url}`);
if (s.required && !s.isHealthy) {
allRequiredHealthy = false;
failedServices.push(s);
}
});

if (allRequiredHealthy) {
console.log('\n✅ Ready! Run: pnpm run test:e2e:basic\n');
process.exit(0);
} else {
console.log('\n❌ Missing required services!\n');
printServiceErrors(failedServices);
process.exit(1);
}
}

runHealthCheck().catch((err) => {
console.error('❌ Error:', err.message);
process.exit(1);
});
Loading
Loading