diff --git a/e2e/docs-e2e/.gitignore b/e2e/docs-e2e/.gitignore new file mode 100644 index 00000000000..58786aac756 --- /dev/null +++ b/e2e/docs-e2e/.gitignore @@ -0,0 +1,7 @@ + +# Playwright +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/e2e/docs-e2e/package.json b/e2e/docs-e2e/package.json new file mode 100644 index 00000000000..fc156df6564 --- /dev/null +++ b/e2e/docs-e2e/package.json @@ -0,0 +1,18 @@ +{ + "name": "docs-e2e", + "description": "", + "version": "1.0.0", + "author": "", + "devDependencies": { + "@playwright/test": "1.50.1", + "@types/node": "20.19.0" + }, + "keywords": [], + "license": "ISC", + "main": "index.js", + "scripts": { + "test": "pnpm exec playwright test --config=playwright.config.ts --project=chromium", + "test-ui": "pnpm exec playwright test --config=playwright.config.ts --project=chromium --ui" + }, + "type": "commonjs" +} diff --git a/e2e/docs-e2e/playwright.config.ts b/e2e/docs-e2e/playwright.config.ts new file mode 100644 index 00000000000..00508803c5f --- /dev/null +++ b/e2e/docs-e2e/playwright.config.ts @@ -0,0 +1,85 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** Read environment variables from file. https://github.com/motdotla/dotenv */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** See https://playwright.dev/docs/test-configuration. */ + +const TestingURL = 'http://127.0.0.1:3000'; + +export default defineConfig({ + testDir: './tests', + /* Global timeout for each test */ + timeout: 60_000, + expect: { timeout: 60_000 }, + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: TestingURL, + actionTimeout: 30_000, + navigationTimeout: 60_000, + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + { + name: 'chrome', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'pnpm -C ../../ run docs.dev', + url: TestingURL, + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/e2e/docs-e2e/tests/Docs/advanced-pages-load.spec.ts b/e2e/docs-e2e/tests/Docs/advanced-pages-load.spec.ts new file mode 100644 index 00000000000..cfedb0738f6 --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/advanced-pages-load.spec.ts @@ -0,0 +1,93 @@ +import { test, expect } from '@playwright/test'; + +test('Advanced Dollar Function page loads', async ({ page }) => { + await page.goto('/docs/advanced/dollar/'); + + await expect(page).toHaveTitle('The $ dollar sign | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Containers page loads', async ({ page }) => { + await page.goto('/docs/advanced/containers/'); + await expect(page).toHaveTitle('Containers | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced QRL page loads', async ({ page }) => { + await page.goto('/docs/advanced/qrl/'); + await expect(page).toHaveTitle('QRL | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Library page loads', async ({ page }) => { + await page.goto('/docs/advanced/library/'); + await expect(page).toHaveTitle('Component library | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Qwikloader page loads', async ({ page }) => { + await page.goto('/docs/advanced/qwikloader/'); + await expect(page).toHaveTitle('Qwikloader | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Optimizer page loads', async ({ page }) => { + await page.goto('/docs/advanced/optimizer/'); + await expect(page).toHaveTitle('Optimizer Rules | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Prefetching Modules page loads', async ({ page }) => { + await page.goto('/docs/advanced/modules-prefetching/'); + await expect(page).toHaveTitle('Prefetching | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Custom Build Directory page loads', async ({ page }) => { + await page.goto('/docs/advanced/custom-build-dir/'); + await expect(page).toHaveTitle('Custom Build Output Directory | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Vite page loads', async ({ page }) => { + await page.goto('/docs/advanced/vite/'); + await expect(page).toHaveTitle('Vite | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Routing page loads', async ({ page }) => { + await page.goto('/docs/advanced/routing/'); + await expect(page).toHaveTitle('Advanced Routing | Qwik City ๐ Qwik Documentation'); +}); + +test('Advanced Plugins page loads', async ({ page }) => { + await page.goto('/docs/advanced/plugins/'); + await expect(page).toHaveTitle('Qwik Plugins | Qwik City ๐ Qwik Documentation'); +}); + +test('Advanced Request Handling page loads', async ({ page }) => { + await page.goto('/docs/advanced/request-handling/'); + await expect(page).toHaveTitle('Request Handling | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Speculative Module Fetching page loads', async ({ page }) => { + await page.goto('/docs/advanced/speculative-module-fetching/'); + await expect(page).toHaveTitle('Speculative Module Fetching | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Menu page loads', async ({ page }) => { + await page.goto('/docs/advanced/menu/'); + await expect(page).toHaveTitle('Menu | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Generating Sitemaps page loads', async ({ page }) => { + await page.goto('/docs/advanced/sitemaps/'); + await expect(page).toHaveTitle('Generating Sitemaps | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced ESLint-Rules page loads', async ({ page }) => { + await page.goto('/docs/advanced/eslint/'); + // currently does not have a custom title + await expect(page).toHaveTitle('Qwik - Framework reimagined for the edge'); +}); + +test('Advanced Content Security Policy page loads', async ({ page }) => { + await page.goto('/docs/advanced/content-security-policy/'); + await expect(page).toHaveTitle('Content Security Policy | Advanced ๐ Qwik Documentation'); +}); + +test('Advanced Complex Forms page loads', async ({ page }) => { + await page.goto('/docs/advanced/complex-forms/'); + await expect(page).toHaveTitle('Complex Forms | Advanced ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/community-pages.load.spec.ts b/e2e/docs-e2e/tests/Docs/community-pages.load.spec.ts new file mode 100644 index 00000000000..328a377c31f --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/community-pages.load.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from '@playwright/test'; + +test('Community Projects page loads', async ({ page }) => { + await page.goto('/community/projects/'); + await expect(page).toHaveTitle('Projects | Qwik Community ๐ Qwik Documentation'); +}); + +test('Community Groups page loads', async ({ page }) => { + await page.goto('/community/groups/'); + await expect(page).toHaveTitle('Groups | Qwik Community ๐ Qwik Documentation'); +}); + +test('Community Values page loads', async ({ page }) => { + await page.goto('/community/values/'); + await expect(page).toHaveTitle('Values | Qwik Community ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/concepts-pages-laod.spec.ts b/e2e/docs-e2e/tests/Docs/concepts-pages-laod.spec.ts new file mode 100644 index 00000000000..6f5109b8d5e --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/concepts-pages-laod.spec.ts @@ -0,0 +1,21 @@ +import { test, expect } from '@playwright/test'; + +test('Concepts Think Qwik page loads', async ({ page }) => { + await page.goto('/docs/concepts/think-qwik/'); + await expect(page).toHaveTitle('Think Qwik | Concepts ๐ Qwik Documentation'); +}); + +test('Concepts Resumable page loads', async ({ page }) => { + await page.goto('/docs/concepts/resumable/'); + await expect(page).toHaveTitle('Resumable | Concepts ๐ Qwik Documentation'); +}); + +test('Concepts Progressive page loads', async ({ page }) => { + await page.goto('/docs/concepts/progressive/'); + await expect(page).toHaveTitle('Progressive | Concepts ๐ Qwik Documentation'); +}); + +test('Concepts Reactivity page loads', async ({ page }) => { + await page.goto('/docs/concepts/reactivity/'); + await expect(page).toHaveTitle('Reactivity | Concepts ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/cookbook-pages-load.spec.ts b/e2e/docs-e2e/tests/Docs/cookbook-pages-load.spec.ts new file mode 100644 index 00000000000..568decd647a --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/cookbook-pages-load.spec.ts @@ -0,0 +1,73 @@ +import { test, expect } from '@playwright/test'; + +test('Cookbook Overview page loads', async ({ page }) => { + await page.goto('/docs/cookbook/'); + await expect(page).toHaveTitle('Cookbook | Overview ๐ Qwik Documentation'); +}); + +test('Cookbook Algolia Search page loads', async ({ page }) => { + await page.goto('/docs/cookbook/algolia-search/'); + await expect(page).toHaveTitle('Cookbook | Algolia Search ๐ Qwik Documentation'); +}); + +test('Cookbook Combine Request Handlers page loads', async ({ page }) => { + await page.goto('/docs/cookbook/combine-request-handlers/'); + await expect(page).toHaveTitle('Cookbook | Combine Request Handlers ๐ Qwik Documentation'); +}); + +test('Cookbook Debouncer page loads', async ({ page }) => { + await page.goto('/docs/cookbook/debouncer/'); + await expect(page).toHaveTitle('Cookbook | Debouncer ๐ Qwik Documentation'); +}); + +test('Cookbook Fonts page loads', async ({ page }) => { + await page.goto('/docs/cookbook/fonts/'); + await expect(page).toHaveTitle('Cookbook | Font optimization ๐ Qwik Documentation'); +}); + +test('Cookbook Glob Import & Dynamic Import page loads', async ({ page }) => { + await page.goto('/docs/cookbook/glob-import/'); + await expect(page).toHaveTitle( + 'Cookbook | Glob Import with import.meta.glob ๐ Qwik Documentation' + ); +}); + +test('Cookbook NavLink Component page loads', async ({ page }) => { + await page.goto('/docs/cookbook/nav-link/'); + await expect(page).toHaveTitle('Cookbook | Navbar link ๐ Qwik Documentation'); +}); + +test('Cookbook Deploy with Node using Docker page loads', async ({ page }) => { + await page.goto('/docs/cookbook/node-docker-deploy/'); + await expect(page).toHaveTitle('Cookbook | Deploy with Node using Docker ๐ Qwik Documentation'); +}); + +test('Cookbook Portals page loads', async ({ page }) => { + await page.goto('/docs/cookbook/portals/'); + await expect(page).toHaveTitle('Cookbook | Portals ๐ Qwik Documentation'); +}); + +test('Cookbook Streaming/deferred loaders page loads', async ({ page }) => { + await page.goto('/docs/cookbook/streaming-deferred-loaders/'); + await expect(page).toHaveTitle('Cookbook | Streaming/deferred loaders ๐ Qwik Documentation'); +}); + +test('Cookbook sync$ Events page loads', async ({ page }) => { + await page.goto('/docs/cookbook/sync-events/'); + await expect(page).toHaveTitle('Cookbook | Synchronous Events with State ๐ Qwik Documentation'); +}); + +test('Cookbook Theme Management page loads', async ({ page }) => { + await page.goto('/docs/cookbook/theme-management/'); + await expect(page).toHaveTitle('Cookbook | Dark and Light Theme ๐ Qwik Documentation'); +}); + +test('Cookbook Drag & Drop page loads', async ({ page }) => { + await page.goto('/docs/cookbook/drag&drop/'); + await expect(page).toHaveTitle('Cookbook | Drag & Drop ๐ Qwik Documentation'); +}); + +test('Cookbook View Transition API page loads', async ({ page }) => { + await page.goto('/docs/cookbook/view-transition/'); + await expect(page).toHaveTitle('Cookbook | View Transition API ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/deployments-pages-load.spec.ts b/e2e/docs-e2e/tests/Docs/deployments-pages-load.spec.ts new file mode 100644 index 00000000000..79ba8a7394e --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/deployments-pages-load.spec.ts @@ -0,0 +1,67 @@ +import { test, expect } from '@playwright/test'; + +test('Deployments Overview page loads', async ({ page }) => { + await page.goto('/docs/deployments/'); + await expect(page).toHaveTitle('Deployments | Guides ๐ Qwik Documentation'); +}); + +test('Deployments Azure Static Web Apps Middleware page loads', async ({ page }) => { + await page.goto('/docs/deployments/azure-swa/'); + await expect(page).toHaveTitle('Azure Static Web Apps | Deployments ๐ Qwik Documentation'); +}); + +test('Deployments AWS Adapter page loads', async ({ page }) => { + await page.goto('/docs/deployments/aws-lambda/'); + await expect(page).toHaveTitle('AWS Lambda | Deployments ๐ Qwik Documentation'); +}); + +test('Deployments Firebase Adapter page loads', async ({ page }) => { + await page.goto('/docs/deployments/firebase/'); + await expect(page).toHaveTitle('Firebase | Deployments ๐ Qwik Documentation'); +}); + +test('Deployments Google Cloud Run Middleware page loads', async ({ page }) => { + await page.goto('/docs/deployments/gcp-cloud-run/'); + await expect(page).toHaveTitle('Cloud Run Middleware | Deployments ๐ Qwik Documentation'); +}); + +test('Deployments Cloudflare Pages Adapter page loads', async ({ page }) => { + await page.goto('/docs/deployments/cloudflare-pages/'); + await expect(page).toHaveTitle( + 'Cloudflare Pages Adapter and Middleware | Deployments ๐ Qwik Documentation' + ); +}); + +test('Deployments Deno Middleware page loads', async ({ page }) => { + await page.goto('/docs/deployments/deno/'); + await expect(page).toHaveTitle('Deno Middleware | Deployments ๐ Qwik Documentation'); +}); + +test('Deployments Bun Middleware page loads', async ({ page }) => { + await page.goto('/docs/deployments/bun/'); + await expect(page).toHaveTitle('Bun Middleware | Deployments ๐ Qwik Documentation'); +}); + +test('Deployments Netlify Edge Adapter page loads', async ({ page }) => { + await page.goto('/docs/deployments/netlify-edge/'); + await expect(page).toHaveTitle( + 'Netlify Edge Adapter and Middleware | Deployments ๐ Qwik Documentation' + ); +}); + +test('Deployments Node Middleware page loads', async ({ page }) => { + await page.goto('/docs/deployments/node/'); + await expect(page).toHaveTitle('Node Middleware | Deployments ๐ Qwik Documentation'); +}); + +test('Deployments Vercel Edge Adapter page loads', async ({ page }) => { + await page.goto('/docs/deployments/vercel-edge/'); + await expect(page).toHaveTitle( + 'Vercel Edge Adapter and Middleware | Deployments ๐ Qwik Documentation' + ); +}); + +test('Deployments Static Site Adapter page loads', async ({ page }) => { + await page.goto('/docs/deployments/static/'); + await expect(page).toHaveTitle('Static Site ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/docs-components-pages-load.spec.ts b/e2e/docs-e2e/tests/Docs/docs-components-pages-load.spec.ts new file mode 100644 index 00000000000..30def72d593 --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/docs-components-pages-load.spec.ts @@ -0,0 +1,43 @@ +import { test, expect } from '@playwright/test'; + +test('Components Overview page loads', async ({ page }) => { + await page.goto('/docs/components/overview/'); + await expect(page).toHaveTitle('Overview | Components ๐ Qwik Documentation'); +}); + +test('Components State page loads', async ({ page }) => { + await page.goto('/docs/components/state/'); + await expect(page).toHaveTitle('State | Components ๐ Qwik Documentation'); +}); + +test('Components Tasks and Lifecycle page loads', async ({ page }) => { + await page.goto('/docs/components/tasks/'); + await expect(page).toHaveTitle('Tasks and Lifecycle | Components ๐ Qwik Documentation'); +}); + +test('Components Context page loads', async ({ page }) => { + await page.goto('/docs/components/context/'); + await expect(page).toHaveTitle('Context | Components ๐ Qwik Documentation'); +}); + +test('Components Slots page loads', async ({ page }) => { + await page.goto('/docs/components/slots/'); + await expect(page).toHaveTitle('Slots | Components ๐ Qwik Documentation'); +}); + +test('Components Rendering page loads', async ({ page }) => { + await page.goto('/docs/components/rendering/'); + await expect(page).toHaveTitle('Rendering | Components ๐ Qwik Documentation'); +}); + +test('Components Styles page loads', async ({ page }) => { + await page.goto('/docs/components/styles/'); + await expect(page).toHaveTitle('Styles | Components ๐ Qwik Documentation'); +}); + +test('Components API Reference page loads', async ({ page }) => { + await page.goto('/api/qwik/'); + + // todo V2: change this to @qwik.dev + await expect(page).toHaveTitle('@builder.io/qwik API Reference ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/guides-pages-load.spec.ts b/e2e/docs-e2e/tests/Docs/guides-pages-load.spec.ts new file mode 100644 index 00000000000..27b1279129a --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/guides-pages-load.spec.ts @@ -0,0 +1,43 @@ +import { test, expect } from '@playwright/test'; + +test('Guides Qwik in a nutshell page loads', async ({ page }) => { + await page.goto('/docs/guides/qwik-nutshell/'); + await expect(page).toHaveTitle('Qwik in a nutshell | Introduction ๐ Qwik Documentation'); +}); + +test('Guides MDX page loads', async ({ page }) => { + await page.goto('/docs/guides/mdx/'); + await expect(page).toHaveTitle('Markdown and MDX | Guides ๐ Qwik Documentation'); +}); + +test('Guides SSG page loads', async ({ page }) => { + await page.goto('/docs/guides/static-site-generation/'); + await expect(page).toHaveTitle( + 'Static Site Generation (SSG) Overview | Guides ๐ Qwik Documentation' + ); +}); + +test('Guides Capacitor page loads', async ({ page }) => { + await page.goto('/docs/guides/capacitor/'); + await expect(page).toHaveTitle('Qwik Hybrid Native App Overview | Guides ๐ Qwik Documentation'); +}); + +test('Guides React Cheat Sheet page loads', async ({ page }) => { + await page.goto('/docs/guides/react-cheat-sheet/'); + await expect(page).toHaveTitle('Qwik for React developers ๐ Qwik Documentation'); +}); + +test('Guides Best Practices page loads', async ({ page }) => { + await page.goto('/docs/guides/best-practices/'); + await expect(page).toHaveTitle('Best Practices | Guides ๐ Qwik Documentation'); +}); + +test('Guides Bundle Optimization page loads', async ({ page }) => { + await page.goto('/docs/guides/bundle/'); + await expect(page).toHaveTitle('Bundle Optimization | Guides ๐ Qwik Documentation'); +}); + +test('Guides Environment Variables page loads', async ({ page }) => { + await page.goto('/docs/guides/env-variables/'); + await expect(page).toHaveTitle('Environment variables | Qwik City ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/integrations-pages-load.spec.ts b/e2e/docs-e2e/tests/Docs/integrations-pages-load.spec.ts new file mode 100644 index 00000000000..d580c8457b6 --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/integrations-pages-load.spec.ts @@ -0,0 +1,141 @@ +import { test, expect } from '@playwright/test'; + +test('Integrations Overview page loads', async ({ page }) => { + await page.goto('/docs/integrations/'); + await expect(page).toHaveTitle('Qwik City Integrations | Guides ๐ Qwik Documentation'); +}); + +test('Integrations Astro page loads', async ({ page }) => { + await page.goto('/docs/integrations/astro/'); + await expect(page).toHaveTitle('Astro | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Auth.js page loads', async ({ page }) => { + await page.goto('/docs/integrations/authjs/'); + await expect(page).toHaveTitle('Auth.js | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Bootstrap page loads', async ({ page }) => { + await page.goto('/docs/integrations/bootstrap/'); + await expect(page).toHaveTitle('Bootstrap | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Builder.io page loads', async ({ page }) => { + await page.goto('/docs/integrations/builderio/'); + await expect(page).toHaveTitle('Builder.io | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Cypress page loads', async ({ page }) => { + await page.goto('/docs/integrations/cypress/'); + await expect(page).toHaveTitle('Cypress | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Drizzle page loads', async ({ page }) => { + await page.goto('/docs/integrations/drizzle/'); + await expect(page).toHaveTitle('Drizzle | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Internationalization page loads', async ({ page }) => { + await page.goto('/docs/integrations/i18n/'); + await expect(page).toHaveTitle('Internationalization | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Icons page loads', async ({ page }) => { + await page.goto('/docs/integrations/icons/'); + await expect(page).toHaveTitle('Icons | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Image Optimization page loads', async ({ page }) => { + await page.goto('/docs/integrations/image-optimization/'); + await expect(page).toHaveTitle('Image Optimization | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations LeafletJS Map page loads', async ({ page }) => { + await page.goto('/docs/integrations/leaflet-map/'); + await expect(page).toHaveTitle('LeafletJS Map | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Modular Forms page loads', async ({ page }) => { + await page.goto('/docs/integrations/modular-forms/'); + await expect(page).toHaveTitle('Modular Forms | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Nx and enterprise scale monorepos page loads', async ({ page }) => { + await page.goto('/docs/integrations/nx/'); + await expect(page).toHaveTitle('Nx Monorepos | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations OG Image / Open Graph Image page loads', async ({ page }) => { + await page.goto('/docs/integrations/og-img/'); + await expect(page).toHaveTitle('OG Image (og-img) | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Orama page loads', async ({ page }) => { + await page.goto('/docs/integrations/orama/'); + await expect(page).toHaveTitle('Qwik City and Orama ๐ Qwik Documentation'); +}); + +test('Integrations Panda CSS page loads', async ({ page }) => { + await page.goto('/docs/integrations/panda-css/'); + await expect(page).toHaveTitle('Panda CSS | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Partytown page loads', async ({ page }) => { + await page.goto('/docs/integrations/partytown/'); + await expect(page).toHaveTitle('Partytown | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Playwright page loads', async ({ page }) => { + await page.goto('/docs/integrations/playwright/'); + await expect(page).toHaveTitle('Playwright | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations PostCSS page loads', async ({ page }) => { + await page.goto('/docs/integrations/postcss/'); + await expect(page).toHaveTitle('PostCSS | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Prisma page loads', async ({ page }) => { + await page.goto('/docs/integrations/prisma/'); + await expect(page).toHaveTitle('Prisma | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Qwik React page loads', async ({ page }) => { + await page.goto('/docs/integrations/react/'); + await expect(page).toHaveTitle('React | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Storybook page loads', async ({ page }) => { + await page.goto('/docs/integrations/storybook/'); + await expect(page).toHaveTitle('Storybook | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Styled Vanilla Extract page loads', async ({ page }) => { + await page.goto('/docs/integrations/styled-vanilla-extract/'); + await expect(page).toHaveTitle('Styled Vanilla Extract | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Supabase page loads', async ({ page }) => { + await page.goto('/docs/integrations/supabase/'); + await expect(page).toHaveTitle('Supabase | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Tailwind page loads', async ({ page }) => { + await page.goto('/docs/integrations/tailwind/'); + await expect(page).toHaveTitle('Tailwind | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Tauri page loads', async ({ page }) => { + await page.goto('/docs/integrations/tauri/'); + await expect(page).toHaveTitle('Tauri | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Turso page loads', async ({ page }) => { + await page.goto('/docs/integrations/turso/'); + await expect(page).toHaveTitle('Turso | Integrations ๐ Qwik Documentation'); +}); + +test('Integrations Vitest page loads', async ({ page }) => { + await page.goto('/docs/integrations/vitest/'); + await expect(page).toHaveTitle('Vitest | Integrations ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/navBarOnMobile.spec.ts b/e2e/docs-e2e/tests/Docs/navBarOnMobile.spec.ts new file mode 100644 index 00000000000..5975f4c1482 --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/navBarOnMobile.spec.ts @@ -0,0 +1,40 @@ +import { test, expect, devices } from '@playwright/test'; + +test.use({ + ...devices['iPhone 13'], +}); + +test('navbar on mobile', async ({ page }) => { + await page.goto('/'); + const openIcon = page.locator('.mobile-menu > .more-icon > svg'); + const closeIcon = page.locator('.mobile-menu > .close-icon > svg'); + const navToolKit = page.locator('.menu-toolkit'); + const body = page.locator('body'); + + expect(body).not.toHaveClass('header-open'); + await expect(openIcon).toBeVisible(); + await openIcon.click(); + expect(body).toHaveClass('header-open'); + await expect(closeIcon).toBeVisible(); + + await expect(navToolKit).toBeVisible(); + const menuItems = await page.locator('.menu-toolkit > li > a').allTextContents(); + const expectedMenuLinks = [ + 'Docs', + 'Ecosystem', + 'Tutorial', + 'Qwik Sandbox', + 'Blog', + 'GitHub', + '@QwikDev', + 'Discord', + ]; + + expect(menuItems).toStrictEqual(expectedMenuLinks); + + await closeIcon.click(); + expect(body).not.toHaveClass('header-open'); + await expect(closeIcon).not.toBeVisible(); + await expect(openIcon).toBeVisible(); + await expect(navToolKit).not.toBeVisible(); +}); diff --git a/e2e/docs-e2e/tests/Docs/pages-load-test.spec.ts b/e2e/docs-e2e/tests/Docs/pages-load-test.spec.ts new file mode 100644 index 00000000000..1720624cc71 --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/pages-load-test.spec.ts @@ -0,0 +1,258 @@ +import { test, expect } from '@playwright/test'; + +test('home page loads', async ({ page }) => { + await page.goto('/'); + await expect(page).toHaveTitle('Framework reimagined for the edge! ๐ Qwik Documentation'); +}); + +test('docs page loads', async ({ page }) => { + await page.goto('/docs/'); + + await expect(page).toHaveTitle('Overview | Introduction ๐ Qwik Documentation'); + + const introductionLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Introduction")) ul li a') + .allTextContents(); + + const expectedIntroductionLinks = ['Overview', 'Getting Started', 'Project structure', 'FAQ']; + + expect(introductionLinksOnPage).toStrictEqual(expectedIntroductionLinks); + + const componentsLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Components")) ul li a') + .allTextContents(); + + const expectedComponentLinks = [ + 'Overview', + 'State', + 'Events', + 'Tasks & Lifecycle', + 'Context', + 'Slots', + 'Rendering', + 'Styling', + 'API Reference', + ]; + + expect(componentsLinksOnPage).toStrictEqual(expectedComponentLinks); + + const qwikCityLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Qwik City")) ul li a') + .allTextContents(); + + const expectedQwikCityLinks = [ + 'Overview', + 'Routing', + 'Pages', + 'Layouts', + 'Loaders', + 'Actions', + 'Validators', + 'Endpoints', + 'Middleware', + 'server$', + 'Error handling', + 'Re-exporting loaders', + 'Caching', + 'HTML attributes', + 'API reference', + ]; + + expect(qwikCityLinksOnPage).toStrictEqual(expectedQwikCityLinks); + + const cookbookLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Cookbook")) ul li a') + .allTextContents(); + + const expectedCookbookLinks = [ + 'Overview', + 'Algolia Search', + 'Combine Handlers', + 'Debouncer', + 'Fonts', + 'Glob Import', + 'Media Controller', + 'NavLink', + 'Node Docker deploy', + 'Portals', + 'Streaming loaders', + 'Sync events w state', + 'Theme Management', + 'Drag & Drop', + 'View Transition', + ]; + + // if you are adding a new page to the cookbook, please add a new test for the page to load too + expect(cookbookLinksOnPage).toStrictEqual(expectedCookbookLinks); + + const integrationsLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Integrations")) ul li a') + .allTextContents(); + + const expectedIntegrationsLinks = [ + 'Overview', + 'Astro', + 'Auth.js', + 'Bootstrap', + 'Builder.io', + 'Cypress', + 'Drizzle', + 'i18n', + 'Icons', + 'Image Optimization', + 'Leaflet Map', + 'Modular Forms', + 'Nx Monorepos', + 'OG Image', + 'Orama', + 'Panda CSS', + 'Partytown', + 'Playwright', + 'PostCSS', + 'Prisma', + 'React', + 'Storybook', + 'Styled Vanilla Extract', + 'Supabase', + 'Tailwind', + 'Tauri', + 'Turso', + 'Vitest', + ]; + + expect(integrationsLinksOnPage).toStrictEqual(expectedIntegrationsLinks); + + const deploymentsLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Deployments")) ul li a') + .allTextContents(); + + const expectedDeploymentsLinks = [ + 'Overview', + 'Azure SWA', + 'AWS', + 'Firebase', + 'Google Cloud Run', + 'Cloudflare Pages', + 'Deno', + 'Bun', + 'Netlify Edge', + 'Node', + 'Self-Hosting', + 'Vercel Edge', + 'Static Site', + 'Azion', + ]; + + expect(deploymentsLinksOnPage).toStrictEqual(expectedDeploymentsLinks); + + const guidesLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Guides")) ul li a') + .allTextContents(); + + const expectedGuidesLinks = [ + 'Qwik in a nutshell', + 'Markdown & MDX', + 'SSG', + 'Qwik Native Apps', + 'React Cheat Sheet', + 'Debugging', + 'Best Practices', + 'Bundle Optimization', + 'Env variables', + ]; + + expect(guidesLinksOnPage).toStrictEqual(expectedGuidesLinks); + + const conceptsLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Concepts")) ul li a') + .allTextContents(); + + const expectedConceptsLinks = ['Think Qwik', 'Resumable', 'Progressive', 'Reactivity']; + + expect(conceptsLinksOnPage).toStrictEqual(expectedConceptsLinks); + + const advancedLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Advanced")) ul li a') + .allTextContents(); + + const expectedAdvancedLinks = [ + 'The $ dollar sign', + 'Containers', + 'QRL', + 'Library mode', + 'Qwikloader', + 'Optimizer', + 'Modules Prefetching', + 'Build Directory', + 'Vite', + 'Advanced Routing', + 'Qwik Plugins', + 'Request Handling', + 'Speculative Module Fetching', + 'Menus', + 'Static Assets', + 'Sitemaps', + 'ESLint-Rules', + 'Content Security Policy', + 'Complex Forms', + ]; + + expect(advancedLinksOnPage).toStrictEqual(expectedAdvancedLinks); + + const referenceLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Reference")) ul li a') + .allTextContents(); + + const expectedReferenceLinks = ['API Reference', 'Deprecated Features']; + + expect(referenceLinksOnPage).toStrictEqual(expectedReferenceLinks); + + const qwikLabsLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Qwik Labs ๐งช")) ul li a') + .allTextContents(); + + const expectedQwikLabsLinks = [ + 'Overview', + 'Insights', + 'Typed Routes', + 'Devtools', + 'usePreventNavigate', + ]; + + expect(qwikLabsLinksOnPage).toStrictEqual(expectedQwikLabsLinks); + + const communityLinksOnPage = await page + .locator('#qwik-sidebar') + .locator('details:has(summary h5:text("Community")) ul li a') + .allTextContents(); + + const expectedCommunityLinks = ['GitHub', '@QwikDev', 'Discord', 'Community Projects', 'Values']; + + expect(communityLinksOnPage).toStrictEqual(expectedCommunityLinks); +}); + +test('getting started page loads', async ({ page }) => { + await page.goto('/docs/getting-started/'); + await expect(page).toHaveTitle('Getting Started | Introduction ๐ Qwik Documentation'); +}); + +test('Project Structure page loads', async ({ page }) => { + await page.goto('/docs/project-structure/'); + await expect(page).toHaveTitle('Project Structure | Qwik City ๐ Qwik Documentation'); +}); + +test('FAQ page loads', async ({ page }) => { + await page.goto('/docs/faq/'); + await expect(page).toHaveTitle('Frequently Asked Questions | Introduction ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/qwik-city-pages-load.spec.ts b/e2e/docs-e2e/tests/Docs/qwik-city-pages-load.spec.ts new file mode 100644 index 00000000000..23ad08e0d91 --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/qwik-city-pages-load.spec.ts @@ -0,0 +1,68 @@ +// todo V2: rename file to qwik-router-pages-load.spec.ts +// todo V2: replace all instances of Qwik City with Qwik Router +import { test, expect } from '@playwright/test'; + +test('Qwik City Overview page loads', async ({ page }) => { + await page.goto('/docs/qwikcity/'); + await expect(page).toHaveTitle('Overview | Qwik City ๐ Qwik Documentation'); +}); + +test('Qwik City Routing page loads', async ({ page }) => { + await page.goto('/docs/routing/'); + await expect(page).toHaveTitle('Routing | Qwik City ๐ Qwik Documentation'); +}); + +test('Qwik City Pages page loads', async ({ page }) => { + await page.goto('/docs/pages/'); + await expect(page).toHaveTitle('Pages | Qwik City ๐ Qwik Documentation'); +}); + +test('Qwik City Layout page loads', async ({ page }) => { + await page.goto('/docs/layout/'); + await expect(page).toHaveTitle('Layout & Middleware | Guides ๐ Qwik Documentation'); +}); + +test('Qwik City Route Loader page loads', async ({ page }) => { + await page.goto('/docs/route-loader/'); + await expect(page).toHaveTitle('RouteLoader$ | Qwik City ๐ Qwik Documentation'); +}); + +test('Qwik City Route Action page loads', async ({ page }) => { + await page.goto('/docs/action/'); + await expect(page).toHaveTitle('RouteAction$ | QwikCity ๐ Qwik Documentation'); +}); + +test('Qwik City Endpoints page loads', async ({ page }) => { + await page.goto('/docs/endpoints/'); + await expect(page).toHaveTitle('Endpoints | Qwik City ๐ Qwik Documentation'); +}); + +test('Qwik City Middleware page loads', async ({ page }) => { + await page.goto('/docs/middleware/'); + await expect(page).toHaveTitle('Middleware | Guides ๐ Qwik Documentation'); +}); + +test('Qwik City server$ page loads', async ({ page }) => { + await page.goto('/docs/server$/'); + await expect(page).toHaveTitle('server$ | Qwik City ๐ Qwik Documentation'); +}); + +test('Qwik City Error Handling page loads', async ({ page }) => { + await page.goto('/docs/error-handling/'); + await expect(page).toHaveTitle('Error handling | Qwik City ๐ Qwik Documentation'); +}); + +test('Qwik City Re-exporting Loaders page loads', async ({ page }) => { + await page.goto('/docs/re-exporting-loaders/'); + await expect(page).toHaveTitle('Cookbook | Re-exporting loaders ๐ Qwik Documentation'); +}); + +test('Qwik City HTML Attributes page loads', async ({ page }) => { + await page.goto('/docs/html-attributes/'); + await expect(page).toHaveTitle('HTML attributes | QwikCity ๐ Qwik Documentation'); +}); + +test('Qwik City API Reference page loads', async ({ page }) => { + await page.goto('/docs/api/'); + await expect(page).toHaveTitle('API Reference | Qwik City ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/qwik-labs-pages-load.spec.ts b/e2e/docs-e2e/tests/Docs/qwik-labs-pages-load.spec.ts new file mode 100644 index 00000000000..0678a0b83c5 --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/qwik-labs-pages-load.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from '@playwright/test'; + +test('Qwik Labs Overview page loads', async ({ page }) => { + await page.goto('/docs/labs/'); + await expect(page).toHaveTitle('๐งช Qwik Labs | Overview ๐ Qwik Documentation'); +}); + +test('Qwik Labs Insights page loads', async ({ page }) => { + await page.goto('/docs/labs/insights/'); + await expect(page).toHaveTitle('๐งช Insights | Qwik Labs ๐ Qwik Documentation'); +}); + +test('Qwik Labs usePreventNavigate page loads', async ({ page }) => { + await page.goto('/docs/labs/usePreventNavigate/'); + await expect(page).toHaveTitle('๐งช usePreventNavigate | Qwik Labs ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/reference-pages-load.spec.ts b/e2e/docs-e2e/tests/Docs/reference-pages-load.spec.ts new file mode 100644 index 00000000000..39522964311 --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/reference-pages-load.spec.ts @@ -0,0 +1,11 @@ +import { test, expect } from '@playwright/test'; + +test('API Reference page loads', async ({ page }) => { + await page.goto('/api/'); + await expect(page).toHaveTitle('Qwik - Framework reimagined for the edge'); +}); + +test('API Reference Deprecated Features page loads', async ({ page }) => { + await page.goto('/docs/deprecated-features/'); + await expect(page).toHaveTitle('Deprecated Features | Guides ๐ Qwik Documentation'); +}); diff --git a/e2e/docs-e2e/tests/Docs/searchBar.spec.ts b/e2e/docs-e2e/tests/Docs/searchBar.spec.ts new file mode 100644 index 00000000000..8c00aeaa0e5 --- /dev/null +++ b/e2e/docs-e2e/tests/Docs/searchBar.spec.ts @@ -0,0 +1,29 @@ +import { test, expect } from '@playwright/test'; + +test('search bar with click results', async ({ page }) => { + await page.goto('/'); + await page.getByRole('button', { name: 'Search' }).click(); + await page.getByPlaceholder('Search docs').fill('getting started qwikly'); + await page.waitForSelector('.DocSearch-Hit', { timeout: 5000 }); + const countOfSearchResults = await page.locator('.DocSearch-Hit').count(); + expect(countOfSearchResults).toBeGreaterThan(0); + await page.getByRole('link', { name: 'Getting Started Qwikly', exact: true }).click(); + await expect(page).toHaveURL('docs/getting-started/#getting-started-qwikly'); +}); + +test('search with no results', async ({ page }) => { + await page.goto('/'); + await page.getByRole('button', { name: 'Search' }).click(); + await page.getByPlaceholder('Search docs').fill('xyz123nonexistentquery'); + await page.waitForTimeout(1000); + const noResults = page.locator('.DocSearch-NoResults, .DocSearch-EmptyState'); + await expect(noResults).toBeVisible(); +}); + +test('search bar opens and closes', async ({ page }) => { + await page.goto('/'); + await page.getByRole('button', { name: 'Search' }).click(); + await expect(page.getByPlaceholder('Search docs')).toBeVisible(); + await page.keyboard.press('Escape'); + await expect(page.getByPlaceholder('Search docs')).not.toBeVisible(); +}); diff --git a/e2e/docs-e2e/tests/Ecosystem/ecosystem-pages-load.spec.ts b/e2e/docs-e2e/tests/Ecosystem/ecosystem-pages-load.spec.ts new file mode 100644 index 00000000000..9f6cf8ea22e --- /dev/null +++ b/e2e/docs-e2e/tests/Ecosystem/ecosystem-pages-load.spec.ts @@ -0,0 +1,13 @@ +import { test, expect } from '@playwright/test'; + +test('Ecosystem page loads', async ({ page }) => { + await page.goto('/ecosystem//'); + await expect(page).toHaveTitle('Qwik Ecosystem ๐ Qwik Documentation'); +}); + +test('Ecosystem Media Blogs Page loads', async ({ page }) => { + await page.goto('/media/'); + await expect(page).toHaveTitle( + 'Qwik Presentations, Talks, Videos and Podcasts ๐ Qwik Documentation' + ); +}); diff --git a/e2e/docs-e2e/tests/Sandbox/autoComplete.spec.ts b/e2e/docs-e2e/tests/Sandbox/autoComplete.spec.ts new file mode 100644 index 00000000000..04d35a67c28 --- /dev/null +++ b/e2e/docs-e2e/tests/Sandbox/autoComplete.spec.ts @@ -0,0 +1,132 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Sandbox Auto-complete Example', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/examples/reactivity/auto-complete/'); + }); + + test('Sandbox Auto-complete page loads', async ({ page }) => { + await expect(page).toHaveTitle('Auto-complete ๐ Qwik Documentation'); + const tabButtonsTop = page.getByText('app.tsxentry.server.tsxroot.'); + + await expect(tabButtonsTop.getByRole('button')).toHaveCount(3); + await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); + + const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); + await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); + + await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); + + const consoleTabBottom = page.getByText('ConsoleOptions'); + await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); + await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); + await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); + }); + + test('Auto-complete app.tsx loads', async ({ page }) => { + const replInputAppTsx = page + .getByRole('code') + .locator('div') + .filter({ hasText: 'export default component$' }) + .nth(4); + await expect(replInputAppTsx).toBeVisible(); + const serverEntryButton = page.getByRole('button', { name: 'entry.server.tsx' }); + serverEntryButton.click(); + await expect(replInputAppTsx).not.toBeVisible(); + const appTsxButton = page.getByRole('button', { name: 'app.tsx' }); + appTsxButton.click(); + await expect(replInputAppTsx).toBeVisible(); + }); + + test('Auto-complete entry.server.tsx loads', async ({ page }) => { + const root = page + .getByRole('code') + .locator('div') + .filter({ hasText: "import { Root } from './root';" }) + .nth(4); + + await expect(root).not.toBeVisible(); + const button = page.getByRole('button', { name: 'entry.server.tsx' }); + button.click(); + await expect(root).toBeVisible(); + }); + + test('Auto-complete root.tsx loads', async ({ page }) => { + const importStatement = page + .getByRole('code') + .locator('div') + .filter({ hasText: "import App from './app';" }) + .nth(4); + await expect(importStatement).not.toBeVisible(); + const button = page.getByRole('button', { name: 'root.tsx' }); + await button.click(); + await expect(importStatement).toBeVisible(); + }); + + test('Auto-complete HTML Button', async ({ page }) => { + const spinner = page.locator('.repl-spinner'); + await expect(spinner).toBeVisible(); + await expect(spinner).not.toBeVisible(); + const button = page.getByRole('button', { name: 'HTML' }); + await button.click(); + const htmlCode = page.locator('code.language-html'); + await expect(htmlCode).toBeVisible(); + await expect(htmlCode).toContainText(''); + }); + + test('Auto-complete Symbols Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Symbols' }); + await expect(button).toBeVisible(); + await button.click(); + + const symbolsText = page.getByText('import { _jsxQ } from').first(); + await expect(symbolsText).toBeVisible(); + }); + + test('Auto-complete Client Bundles Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Client Bundles' }); + await expect(button).toBeVisible(); + await button.click(); + const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); + await expect(bundles).toBeVisible(); + }); + + test('Auto-complete SSR Module Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'SSR Module' }); + await expect(button).toBeVisible(); + await button.click(); + const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); + await expect(module).toBeVisible(); + }); + + test('Auto-complete Diagnostics Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Diagnostics' }); + await expect(button).toBeVisible(); + await button.click(); + const diagnostics = page.locator('.output-result.output-diagnostics'); + await expect(diagnostics).toBeVisible(); + await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); + }); + + test('Auto-complete Options Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Options' }); + const serverConsoleText = page.getByText('๐ด Paused in server'); + await expect(serverConsoleText).toBeVisible(); + await expect(button).toBeVisible(); + await button.click(); + await expect(serverConsoleText).not.toBeVisible(); + const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); + await expect(DebugCheckBox).toBeVisible(); + await expect(DebugCheckBox).not.toBeChecked(); + const consoleButton = page.getByRole('button', { name: 'Console' }); + consoleButton.click(); + await expect(serverConsoleText).toBeVisible(); + }); +}); diff --git a/e2e/docs-e2e/tests/Sandbox/clockVisible.spec.ts b/e2e/docs-e2e/tests/Sandbox/clockVisible.spec.ts new file mode 100644 index 00000000000..3dfa2517e33 --- /dev/null +++ b/e2e/docs-e2e/tests/Sandbox/clockVisible.spec.ts @@ -0,0 +1,161 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Sandbox Clock Example', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/examples/visibility/clock/'); + }); + + test('Sandbox Clock page loads', async ({ page }) => { + await expect(page).toHaveTitle('Below the fold Clock ๐ Qwik Documentation'); + const tabButtonsTop = page.getByText('app.tsxclock.cssentry.server.'); + + await expect(tabButtonsTop.getByRole('button')).toHaveCount(4); + await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'clock.css' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); + + const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); + await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); + + await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); + + const consoleTabBottom = page.getByText('ConsoleOptions'); + await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); + await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); + await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); + }); + + test('Clock app.tsx loads', async ({ page }) => { + const replInputAppTsx = page + .getByRole('code') + .locator('div') + .filter({ hasText: 'export default component$' }) + .nth(4); + await expect(replInputAppTsx).toBeVisible(); + const serverEntryButton = page.getByRole('button', { name: 'entry.server.tsx' }); + serverEntryButton.click(); + await expect(replInputAppTsx).not.toBeVisible(); + const appTsxButton = page.getByRole('button', { name: 'app.tsx' }); + appTsxButton.click(); + await expect(replInputAppTsx).toBeVisible(); + }); + + test('Clock Clock.css loads', async ({ page }) => { + const clockCSS = page.getByText('background: #fff;'); + const button = page.getByRole('button', { name: 'clock.css' }); + await expect(clockCSS).not.toBeVisible(); + button.click(); + await expect(clockCSS).toBeVisible(); + }); + + test('Clock entry.server.tsx loads', async ({ page }) => { + const root = page + .getByRole('code') + .locator('div') + .filter({ hasText: "import { Root } from './root';" }) + .nth(4); + + await expect(root).not.toBeVisible(); + const button = page.getByRole('button', { name: 'entry.server.tsx' }); + button.click(); + await expect(root).toBeVisible(); + }); + + test('Clock root.tsx loads', async ({ page }) => { + const importStatement = page + .getByRole('code') + .locator('div') + .filter({ hasText: "import App from './app';" }) + .nth(4); + await expect(importStatement).not.toBeVisible(); + const button = page.getByRole('button', { name: 'root.tsx' }); + await button.click(); + await expect(importStatement).toBeVisible(); + }); + + test('Clock HTML Button', async ({ page }) => { + const spinner = page.locator('.repl-spinner'); + await expect(spinner).toBeVisible(); + await expect(spinner).not.toBeVisible(); + const button = page.getByRole('button', { name: 'HTML' }); + await button.click(); + const htmlCode = page.locator('code.language-html'); + await expect(htmlCode).toBeVisible(); + await expect(htmlCode).toContainText(''); + }); + + test('Clock Symbols Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Symbols' }); + await expect(button).toBeVisible(); + await button.click(); + + const symbolsText = page.getByText('import { _jsxQ } from').first(); + await expect(symbolsText).toBeVisible(); + }); + + test('Clock Client Bundles Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Client Bundles' }); + await expect(button).toBeVisible(); + await button.click(); + const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); + await expect(bundles).toBeVisible(); + }); + + test('Clock SSR Module Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'SSR Module' }); + await expect(button).toBeVisible(); + await button.click(); + const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); + await expect(module).toBeVisible(); + }); + + test('Clock Diagnostics Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Diagnostics' }); + await expect(button).toBeVisible(); + await button.click(); + const diagnostics = page.locator('.output-result.output-diagnostics'); + await expect(diagnostics).toBeVisible(); + await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); + }); + + test('Clock Options Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Options' }); + const serverConsoleText = page.getByText('๐ด Paused in server'); + await expect(serverConsoleText).toBeVisible(); + await expect(button).toBeVisible(); + await button.click(); + await expect(serverConsoleText).not.toBeVisible(); + const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); + await expect(DebugCheckBox).toBeVisible(); + await expect(DebugCheckBox).not.toBeChecked(); + const consoleButton = page.getByRole('button', { name: 'Console' }); + consoleButton.click(); + await expect(serverConsoleText).toBeVisible(); + }); + + test('Clock Visible Task ', async ({ page }) => { + const spinner = page.locator('.repl-spinner'); + + await expect(spinner).toBeVisible(); + await expect(spinner).not.toBeVisible(); + const resumed = page.getByText('๐ข Resumed in client'); + + await expect(resumed).not.toBeVisible(); + const outerFrame = await page.locator('iframe').elementHandle(); + const outerFrameContent = await outerFrame?.contentFrame(); + const innerFrameHandle = await outerFrameContent?.locator('iframe').elementHandle(); + const innerFrame = await innerFrameHandle?.contentFrame(); + + await innerFrame?.evaluate(() => { + window.scrollTo(0, document.body.scrollHeight); + }); + + await expect(resumed).toBeVisible(); + }); +}); diff --git a/e2e/docs-e2e/tests/Sandbox/counter.spec.ts b/e2e/docs-e2e/tests/Sandbox/counter.spec.ts new file mode 100644 index 00000000000..c6160dde0f6 --- /dev/null +++ b/e2e/docs-e2e/tests/Sandbox/counter.spec.ts @@ -0,0 +1,158 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Sandbox Counter Example', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/examples/reactivity/counter/'); + }); + + test('Sandbox Counter page loads', async ({ page }) => { + await expect(page).toHaveTitle('Counter ๐ Qwik Documentation'); + const tabButtonsTop = page.getByText('app.tsxentry.server.tsxroot.'); + + await expect(tabButtonsTop.getByRole('button')).toHaveCount(3); + await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); + + const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); + await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); + + await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); + + const consoleTabBottom = page.getByText('ConsoleOptions'); + await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); + await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); + await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); + }); + + test('Counter app.tsx loads', async ({ page }) => { + const replInputAppTsx = page + .getByRole('code') + .locator('div') + .filter({ hasText: 'export default component$' }) + .nth(4); + await expect(replInputAppTsx).toBeVisible(); + const serverEntryButton = page.getByRole('button', { name: 'entry.server.tsx' }); + serverEntryButton.click(); + await expect(replInputAppTsx).not.toBeVisible(); + const appTsxButton = page.getByRole('button', { name: 'app.tsx' }); + appTsxButton.click(); + await expect(replInputAppTsx).toBeVisible(); + }); + + test('Counter entry.server.tsx loads', async ({ page }) => { + const root = page + .getByRole('code') + .locator('div') + .filter({ hasText: "import { Root } from './root';" }) + .nth(4); + + await expect(root).not.toBeVisible(); + const button = page.getByRole('button', { name: 'entry.server.tsx' }); + button.click(); + await expect(root).toBeVisible(); + }); + + test('Counter root.tsx loads', async ({ page }) => { + const importStatement = page + .getByRole('code') + .locator('div') + .filter({ hasText: "import App from './app';" }) + .nth(4); + await expect(importStatement).not.toBeVisible(); + const button = page.getByRole('button', { name: 'root.tsx' }); + await button.click(); + await expect(importStatement).toBeVisible(); + }); + + test('Counter Click Button', async ({ page }) => { + const spinner = page.locator('.repl-spinner'); + await expect(spinner).toBeVisible(); + await expect(spinner).not.toBeVisible(); + const countValue = page + .locator('iframe') + .contentFrame() + .locator('iframe') + .contentFrame() + .locator('main>p') + .first(); + const button = page + .locator('iframe') + .contentFrame() + .locator('iframe') + .contentFrame() + .getByRole('button', { name: 'Click' }); + const resumed = page.getByText('๐ข Resumed in client'); + await expect(resumed).not.toBeVisible(); + await expect(countValue).toHaveText('Count: 0'); + await button.click(); + + await expect(countValue).toHaveText('Count: 1'); + await expect(resumed).toBeVisible(); + }); + + test('Counter HTML Button', async ({ page }) => { + const spinner = page.locator('.repl-spinner'); + await expect(spinner).toBeVisible(); + await expect(spinner).not.toBeVisible(); + const button = page.getByRole('button', { name: 'HTML' }); + await button.click(); + const htmlCode = page.locator('code.language-html'); + await expect(htmlCode).toBeVisible(); + await expect(htmlCode).toContainText(''); + }); + + test('Counter Symbols Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Symbols' }); + await expect(button).toBeVisible(); + await button.click(); + + const symbolsText = page.getByText('import { _jsxQ } from'); + await expect(symbolsText).toBeVisible(); + }); + + test('Counter Client Bundles Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Client Bundles' }); + await expect(button).toBeVisible(); + await button.click(); + const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); + await expect(bundles).toBeVisible(); + }); + + test('Counter SSR Module Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'SSR Module' }); + await expect(button).toBeVisible(); + await button.click(); + const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); + await expect(module).toBeVisible(); + }); + + test('Counter Diagnostics Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Diagnostics' }); + await expect(button).toBeVisible(); + await button.click(); + const diagnostics = page.locator('.output-result.output-diagnostics'); + await expect(diagnostics).toBeVisible(); + await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); + }); + + test('Counter Options Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Options' }); + const serverConsoleText = page.getByText('๐ด Paused in server'); + await expect(serverConsoleText).toBeVisible(); + await expect(button).toBeVisible(); + await button.click(); + await expect(serverConsoleText).not.toBeVisible(); + const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); + await expect(DebugCheckBox).toBeVisible(); + await expect(DebugCheckBox).not.toBeChecked(); + const consoleButton = page.getByRole('button', { name: 'Console' }); + consoleButton.click(); + await expect(serverConsoleText).toBeVisible(); + }); +}); diff --git a/e2e/docs-e2e/tests/Sandbox/partial.spec.ts b/e2e/docs-e2e/tests/Sandbox/partial.spec.ts new file mode 100644 index 00000000000..39a16cb3cd6 --- /dev/null +++ b/e2e/docs-e2e/tests/Sandbox/partial.spec.ts @@ -0,0 +1,152 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Sandbox Partials HackerNews Example', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/examples/partial/hackernews-index/'); + }); + + test('Partial HackerNews page loads', async ({ page }) => { + await expect(page).toHaveTitle('HackerNews ๐ Qwik Documentation'); + const tabButtonsTop = page.getByText('app.tsxentry.server.tsxhacker'); + + await expect(tabButtonsTop.getByRole('button')).toHaveCount(4); + await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'hacker-news.css' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); + + const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); + await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); + + await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); + + const consoleTabBottom = page.getByText('ConsoleOptions'); + await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); + await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); + await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); + }); + + test('Partial HackerNews app.tsx loads', async ({ page }) => { + const replInputAppTsx = page + .getByRole('code') + .getByText('export const HackerNews = component$'); + await expect(replInputAppTsx).toBeVisible(); + const serverEntryButton = page.getByRole('button', { name: 'entry.server.tsx' }); + serverEntryButton.click(); + await expect(replInputAppTsx).not.toBeVisible(); + const appTsxButton = page.getByRole('button', { name: 'app.tsx' }); + appTsxButton.click(); + await expect(replInputAppTsx).toBeVisible(); + }); + + test('Partial HackerNews entry.server.tsx loads', async ({ page }) => { + const root = page + .getByRole('code') + .locator('div') + .filter({ hasText: "import { Root } from './root';" }) + .nth(4); + + await expect(root).not.toBeVisible(); + const button = page.getByRole('button', { name: 'entry.server.tsx' }); + button.click(); + await expect(root).toBeVisible(); + }); + + test('Partial HackerNews root.tsx loads', async ({ page }) => { + const importStatement = page + .getByRole('code') + .locator('div') + .filter({ hasText: "import { HackerNews } from './app';" }) + .nth(4); + await expect(importStatement).not.toBeVisible(); + const button = page.getByRole('button', { name: 'root.tsx' }); + await button.click(); + await expect(importStatement).toBeVisible(); + }); + + test('Partial HackerNews hacker-news.css loads', async ({ page }) => { + const clockCSS = page.getByText('background-color: #f2f3f5;'); + const button = page.getByRole('button', { name: 'hacker-news.css' }); + await expect(clockCSS).not.toBeVisible(); + button.click(); + await expect(clockCSS).toBeVisible(); + }); + + test('Partial HackerNews fetchRequest Loads', async ({ page }) => { + const linkToNextPage = page + .locator('iframe') + .contentFrame() + .locator('iframe') + .contentFrame() + .getByRole('link', { name: 'Next Page' }); + const spinner = page.locator('.repl-spinner'); + await expect(spinner).toBeVisible(); + await expect(spinner).not.toBeVisible(); + await expect(linkToNextPage).toBeVisible(); + }); + + test('Partial HackerNews HTML Button', async ({ page }) => { + const spinner = page.locator('.repl-spinner'); + await expect(spinner).toBeVisible(); + await expect(spinner).not.toBeVisible(); + const button = page.getByRole('button', { name: 'HTML' }); + await button.click(); + const htmlCode = page.locator('code.language-html'); + await expect(htmlCode).toBeVisible(); + await expect(htmlCode).toContainText(''); + }); + + test('Partial HackerNews Symbols Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Symbols' }); + await expect(button).toBeVisible(); + await button.click(); + + const symbolsText = page.getByText('import { _jsxQ } from').first(); + await expect(symbolsText).toBeVisible(); + }); + + test('Partial HackerNews Client Bundles Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Client Bundles' }); + await expect(button).toBeVisible(); + await button.click(); + const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); + await expect(bundles).toBeVisible(); + }); + + test('Partial HackerNews SSR Module Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'SSR Module' }); + await expect(button).toBeVisible(); + await button.click(); + const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); + await expect(module).toBeVisible(); + }); + + test('Partial HackerNews Diagnostics Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Diagnostics' }); + await expect(button).toBeVisible(); + await button.click(); + const diagnostics = page.locator('.output-result.output-diagnostics'); + await expect(diagnostics).toBeVisible(); + await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); + }); + + test('Clock Options Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Options' }); + const serverConsoleText = page.getByText('๐ด Paused in server'); + await expect(serverConsoleText).toBeVisible(); + await expect(button).toBeVisible(); + await button.click(); + await expect(serverConsoleText).not.toBeVisible(); + const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); + await expect(DebugCheckBox).toBeVisible(); + await expect(DebugCheckBox).not.toBeChecked(); + const consoleButton = page.getByRole('button', { name: 'Console' }); + consoleButton.click(); + await expect(serverConsoleText).toBeVisible(); + }); +}); diff --git a/e2e/docs-e2e/tests/Sandbox/routing.spec.ts b/e2e/docs-e2e/tests/Sandbox/routing.spec.ts new file mode 100644 index 00000000000..8fcc3135b90 --- /dev/null +++ b/e2e/docs-e2e/tests/Sandbox/routing.spec.ts @@ -0,0 +1,64 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Sandbox Routing ', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/examples/introduction/hello-world/'); + const Links = page.locator('.examples-menu a'); + const linkCount = await Links.count(); + expect(linkCount).toBe(8); + }); + + test.afterEach(async ({ page }) => { + const link = page.getByRole('link', { name: '๐ Hello World The simplest' }); + await expect(link).toBeVisible(); + await link.click(); + await expect(page).toHaveTitle('Hello World - Qwik'); + }); + + test('Routing runtime-less link test', async ({ page }) => { + const link = page.getByRole('link', { name: '๐ชถ Runtime-less' }); + await expect(link).toBeVisible(); + await link.click(); + await page.waitForLoadState('networkidle'); + expect(page.url()).toContain('/examples/introduction/runtime-less'); + }); + + test('Routing useTask() link test', async ({ page }) => { + const link = page.getByRole('link', { name: '๐ Simple useTask()' }); + await expect(link).toBeVisible(); + await link.click(); + await page.waitForLoadState('networkidle'); + expect(page.url()).toContain('/examples/reactivity/task/'); + }); + + test('Routing Counter link test', async ({ page }) => { + const link = page.getByRole('link', { name: 'โฒ Counter' }); + await expect(link).toBeVisible(); + await link.click(); + await page.waitForLoadState('networkidle'); + expect(page.url()).toContain('/examples/reactivity/counter/'); + }); + + test('Routing Auto Complete link test', async ({ page }) => { + const link = page.getByRole('link', { name: '๐ฌ Auto-complete' }); + await expect(link).toBeVisible(); + await link.click(); + await page.waitForLoadState('networkidle'); + expect(page.url()).toContain('/examples/reactivity/auto-complete/'); + }); + + test('Routing Below the fold Clock link test', async ({ page }) => { + const link = page.getByRole('link', { name: 'โฐ Below the fold Clock' }); + await expect(link).toBeVisible(); + await link.click(); + await page.waitForLoadState('networkidle'); + expect(page.url()).toContain('/examples/visibility/clock/'); + }); + test('Routing Partials HN link test', async ({ page }) => { + const link = page.getByRole('link', { name: '๐ฐ HackerNews HackerNews' }); + await expect(link).toBeVisible(); + await link.click(); + await page.waitForLoadState('networkidle'); + expect(page.url()).toContain('/examples/partial/hackernews-index/'); + }); +}); diff --git a/e2e/docs-e2e/tests/Sandbox/sandbox.spec.ts b/e2e/docs-e2e/tests/Sandbox/sandbox.spec.ts new file mode 100644 index 00000000000..36412347051 --- /dev/null +++ b/e2e/docs-e2e/tests/Sandbox/sandbox.spec.ts @@ -0,0 +1,316 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Sandbox Hello World Example', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/examples/introduction/hello-world/'); + }); + + test('Sandbox page loads', async ({ page }) => { + await expect(page).toHaveTitle('Hello World ๐ Qwik Documentation'); + const tabButtonsTop = page.getByText('app.tsxentry.server.tsxroot.'); + + await expect(tabButtonsTop.getByRole('button')).toHaveCount(3); + await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); + + const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); + await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); + await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); + + const consoleTabBottom = page.getByText('ConsoleOptions'); + await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); + await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); + await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); + }); + + test('Hello world app loads', async ({ page }) => { + const spinner = page.locator('.repl-spinner'); + await expect(spinner).toBeVisible(); + await expect(spinner).not.toBeVisible(); + const appText = page + .getByRole('main') + .locator('iframe') + .contentFrame() + .locator('iframe') + .contentFrame() + .getByText('Hello Qwik'); + await expect(appText).toBeVisible(); + }); + + test('Hello World app.tsx loads', async ({ page }) => { + const text = page + .getByRole('code') + .locator('div') + .filter({ hasText: 'return
Hello Qwik
;' }) + .nth(4); + await expect(text).toBeVisible(); + }); + + test('Hello World update p tag', async ({ page }) => { + const text = page + .getByRole('code') + .locator('div') + .filter({ hasText: 'returnHello Qwik
;' }) + .nth(4); + await expect(text).toBeVisible(); + await text.click(); + await page.keyboard.press('Home'); + await page.keyboard.press('Shift+End'); + + await page.keyboard.type('returnHello Test 1234
;'); + await expect(text).not.toBeVisible(); + + const appText = page + .getByRole('main') + .locator('iframe') + .first() + .contentFrame() + .locator('iframe') + .first() + .contentFrame() + .getByText('Hello Test 1234'); + await expect(appText).toBeVisible(); + }); + + test('Hello World entry.server.tsx tab works', async ({ page }) => { + const button = page.getByRole('button', { name: 'entry.server.tsx' }); + await expect(button).toBeVisible(); + await button.click(); + + const root = page + .getByRole('code') + .locator('div') + .filter({ hasText: "import { Root } from './root';" }) + .nth(4); + await expect(root).toBeVisible(); + }); + + test('Hello World root.tsx tab works', async ({ page }) => { + const button = page.getByRole('button', { name: 'root.tsx' }); + await expect(button).toBeVisible(); + await button.click(); + const app = page + .getByRole('code') + .locator('div') + .filter({ hasText: "import App from './app';" }) + .nth(4); + await expect(app).toBeVisible(); + }); + + test('Hello world HTML Button', async ({ page }) => { + const htmlButton = page.getByRole('button', { name: 'HTML' }); + await expect(htmlButton).toBeVisible(); + await htmlButton.click(); + const htmlCode = page.locator('code.language-html'); + await expect(htmlCode).toBeVisible(); + await expect(htmlCode).toContainText(''); + }); + + test('Hello world Symbols Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Symbols' }); + await expect(button).toBeVisible(); + await button.click(); + + const symbolsText = page.getByText('import { _jsxQ } from'); + await expect(symbolsText).toBeVisible(); + }); + + test('Hello world Client Bundles Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Client Bundles' }); + await expect(button).toBeVisible(); + await button.click(); + const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); + await expect(bundles).toBeVisible(); + }); + + test('Hello world SSR Module Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'SSR Module' }); + await expect(button).toBeVisible(); + await button.click(); + const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); + await expect(module).toBeVisible(); + }); + + test('Hello world Diagnostics Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Diagnostics' }); + await expect(button).toBeVisible(); + await button.click(); + const diagnostics = page.locator('.output-result.output-diagnostics'); + await expect(diagnostics).toBeVisible(); + await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); + }); + + test('Hello world Console', async ({ page }) => { + const button = page.getByRole('button', { name: 'Console' }); + await expect(button).toBeVisible(); + const serverConsoleText = page.getByText('๐ด Paused in server'); + await expect(serverConsoleText).toBeVisible(); + }); + + test('Hello world Options Button', async ({ page }) => { + const button = page.getByRole('button', { name: 'Options' }); + await expect(button).toBeVisible(); + await button.click(); + const serverConsoleText = page.getByText('๐ด Paused in server'); + await expect(serverConsoleText).not.toBeVisible(); + const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); + await expect(DebugCheckBox).toBeVisible(); + await expect(DebugCheckBox).not.toBeChecked(); + }); +}); + +test.describe('Sandbox Runtime-less Example', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/examples/introduction/runtime-less/'); + }); + test('Sandbox Runtime-less page loads', async ({ page }) => { + await expect(page).toHaveTitle('Runtime-less ๐ Qwik Documentation'); + const tabButtonsTop = page.getByText('app.tsxentry.server.tsxroot.'); + + await expect(tabButtonsTop.getByRole('button')).toHaveCount(3); + await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); + + const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); + await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); + + await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); + await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); + + const consoleTabBottom = page.getByText('ConsoleOptions'); + await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); + await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); + await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); + + const consoleLogSSR = page.getByText('ssr render