|
|
@@ -0,0 +1,206 @@
|
|
|
+const { chromium } = require('playwright');
|
|
|
+
|
|
|
+/**
|
|
|
+ * This script is run as part of the "publish & install" workflow, and performs
|
|
|
+ * browser-based tests of the Vendure Dashboard to ensure it loads and login works.
|
|
|
+ */
|
|
|
+async function runDashboardTests() {
|
|
|
+ console.log('Starting dashboard tests...');
|
|
|
+
|
|
|
+ const browser = await chromium.launch({
|
|
|
+ headless: true,
|
|
|
+ args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
|
+ });
|
|
|
+
|
|
|
+ let page;
|
|
|
+
|
|
|
+ try {
|
|
|
+ page = await browser.newPage();
|
|
|
+
|
|
|
+ // Navigate to the dashboard
|
|
|
+ console.log('Navigating to dashboard...');
|
|
|
+ await page.goto('http://localhost:5173');
|
|
|
+
|
|
|
+ // Wait for the page to load
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
+
|
|
|
+ // Check if the login form is present
|
|
|
+ console.log('Checking for login form...');
|
|
|
+ const loginForm = await page.locator('form').first();
|
|
|
+ if (!loginForm) {
|
|
|
+ throw new Error('Login form not found');
|
|
|
+ }
|
|
|
+
|
|
|
+ // Fill in login credentials - try multiple selectors
|
|
|
+ console.log('Filling login credentials...');
|
|
|
+ const usernameInput = await page
|
|
|
+ .locator(
|
|
|
+ 'input[name="username"], input[type="text"], input[placeholder*="username"], input[placeholder*="Username"]',
|
|
|
+ )
|
|
|
+ .first();
|
|
|
+ const passwordInput = await page
|
|
|
+ .locator(
|
|
|
+ 'input[name="password"], input[type="password"], input[placeholder*="password"], input[placeholder*="Password"]',
|
|
|
+ )
|
|
|
+ .first();
|
|
|
+
|
|
|
+ if (!usernameInput || !passwordInput) {
|
|
|
+ throw new Error('Username or password input fields not found');
|
|
|
+ }
|
|
|
+
|
|
|
+ await usernameInput.fill('superadmin');
|
|
|
+ await passwordInput.fill('superadmin');
|
|
|
+
|
|
|
+ // Submit the form - try multiple selectors
|
|
|
+ console.log('Submitting login form...');
|
|
|
+ const submitButton = await page
|
|
|
+ .locator(
|
|
|
+ 'button[type="submit"], input[type="submit"], button:has-text("Login"), button:has-text("Sign In")',
|
|
|
+ )
|
|
|
+ .first();
|
|
|
+ if (!submitButton) {
|
|
|
+ throw new Error('Submit button not found');
|
|
|
+ }
|
|
|
+ await submitButton.click();
|
|
|
+
|
|
|
+ // Wait for navigation after login
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
+
|
|
|
+ // Check if we're logged in by looking for admin dashboard elements
|
|
|
+ console.log('Verifying successful login...');
|
|
|
+
|
|
|
+ // Wait for dashboard elements to appear with a more robust approach
|
|
|
+ const dashboardSelectors = ['h1:has-text("Dashboard")'];
|
|
|
+
|
|
|
+ // Try to wait for any dashboard element to appear
|
|
|
+ let dashboardElement = null;
|
|
|
+ let foundSelector = null;
|
|
|
+
|
|
|
+ for (const selector of dashboardSelectors) {
|
|
|
+ try {
|
|
|
+ // Wait up to 10 seconds for each selector
|
|
|
+ await page.waitForSelector(selector, { timeout: 10000 });
|
|
|
+ dashboardElement = await page.locator(selector).first();
|
|
|
+ if (dashboardElement && (await dashboardElement.count()) > 0) {
|
|
|
+ foundSelector = selector;
|
|
|
+ console.log(`Found dashboard element with selector: ${selector}`);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ // Continue to next selector
|
|
|
+ console.log(`Selector ${selector} not found, trying next...`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!foundSelector) {
|
|
|
+ // Fallback: check if we're still on a login page
|
|
|
+ const currentUrl = page.url();
|
|
|
+ const pageContent = await page.content();
|
|
|
+
|
|
|
+ if (
|
|
|
+ currentUrl.includes('login') ||
|
|
|
+ currentUrl.includes('auth') ||
|
|
|
+ pageContent.includes('login') ||
|
|
|
+ pageContent.includes('Login')
|
|
|
+ ) {
|
|
|
+ throw new Error('Login failed - still on login page');
|
|
|
+ }
|
|
|
+
|
|
|
+ // If we're not on login page, assume login was successful
|
|
|
+ console.log('Login appears successful - not on login page');
|
|
|
+ } else {
|
|
|
+ console.log('Dashboard loaded successfully');
|
|
|
+ }
|
|
|
+
|
|
|
+ // Take a screenshot for debugging
|
|
|
+ await page.screenshot({ path: '/tmp/dashboard-test-login.png' });
|
|
|
+ console.log('Screenshot saved to /tmp/dashboard-test-login.png');
|
|
|
+
|
|
|
+ // navigate to the product list page by clicking the "Products" link in the sidebar
|
|
|
+ // based on the text label "Products"
|
|
|
+ const productsLink = await page.locator('a:has-text("Products")').first();
|
|
|
+ if (!productsLink) {
|
|
|
+ throw new Error('Products link not found');
|
|
|
+ }
|
|
|
+ await productsLink.click();
|
|
|
+
|
|
|
+ // wait for the page to load and verify we're on the Products page
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
+
|
|
|
+ // Wait for the Products page H1 to appear
|
|
|
+ console.log('Waiting for Products page to load...');
|
|
|
+ try {
|
|
|
+ await page.waitForSelector('h1:has-text("Products")', { timeout: 10000 });
|
|
|
+ console.log('Products page loaded successfully');
|
|
|
+ } catch (e) {
|
|
|
+ throw new Error('Products page did not load - H1 with "Products" text not found');
|
|
|
+ }
|
|
|
+
|
|
|
+ // get a list of the products in the product list page
|
|
|
+ const products = await page.locator('tbody tr').all();
|
|
|
+ console.log(`Found ${products.length} products`);
|
|
|
+
|
|
|
+ // Take a screenshot for debugging
|
|
|
+ await page.screenshot({ path: '/tmp/dashboard-test-products.png' });
|
|
|
+ console.log('Screenshot saved to /tmp/dashboard-test-products.png');
|
|
|
+
|
|
|
+ if (products.length !== 10) {
|
|
|
+ throw new Error('Expected 10 products, but found ' + products.length);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('Dashboard tests passed!');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Dashboard test failed:', error.message);
|
|
|
+ // Take a screenshot on failure
|
|
|
+ try {
|
|
|
+ await page.screenshot({ path: '/tmp/dashboard-test-failure.png' });
|
|
|
+ console.log('Failure screenshot saved to /tmp/dashboard-test-failure.png');
|
|
|
+ } catch (screenshotError) {
|
|
|
+ console.log('Could not save failure screenshot:', screenshotError.message);
|
|
|
+ }
|
|
|
+ throw error;
|
|
|
+ } finally {
|
|
|
+ await browser.close();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Wait for the dashboard to be available
|
|
|
+async function awaitDashboardStartup() {
|
|
|
+ console.log('Checking for availability of Dashboard...');
|
|
|
+ let attempts = 0;
|
|
|
+ const maxAttempts = 30;
|
|
|
+
|
|
|
+ while (attempts < maxAttempts) {
|
|
|
+ try {
|
|
|
+ const response = await fetch('http://localhost:5173');
|
|
|
+ if (response.ok) {
|
|
|
+ console.log('Dashboard is running!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ // Ignore errors and continue polling
|
|
|
+ }
|
|
|
+
|
|
|
+ attempts++;
|
|
|
+ if (attempts < maxAttempts) {
|
|
|
+ console.log('Dashboard not yet available, waiting 2s...');
|
|
|
+ await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ throw new Error('Unable to establish connection to Dashboard server!');
|
|
|
+}
|
|
|
+
|
|
|
+// Main execution
|
|
|
+async function main() {
|
|
|
+ try {
|
|
|
+ await awaitDashboardStartup();
|
|
|
+ await runDashboardTests();
|
|
|
+ process.exit(0);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Dashboard tests failed:', error);
|
|
|
+ process.exit(1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+main();
|