diff --git a/examples/advanced-project-js/.gitignore b/examples/advanced-project-js/.gitignore deleted file mode 100644 index 3c3629e64..000000000 --- a/examples/advanced-project-js/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/examples/advanced-project-js/README.md b/examples/advanced-project-js/README.md index 10eeacd69..40c4081d2 100644 --- a/examples/advanced-project-js/README.md +++ b/examples/advanced-project-js/README.md @@ -1,21 +1,52 @@ # Checkly Monitoring-as-code: Advanced Project -This example project shows how you can use the Checkly CLI in a monitoring as code (MaC) workflow. We are using the -https://checklyhq.com website as a monitoring target. +This example project shows how you can use the Checkly CLI in a monitoring as code (MaC) workflow. -1. Write API Checks and Playwright-powered Browser Checks. +1. Write API Checks and Playwright-powered Browser Checks or fully native Playwright Check Suites. 2. Add Alert Channels, and dry-run your Checks on 20+ global locations. 3. Test -> Deploy: now you have your app monitored around the clock. All from your code base. ``` -npm create checkly@latest -- --template advanced-project +npm create checkly@latest -- --template advanced-project-js ``` ## Project Structure This project has examples of all Checkly check types and showcases some advanced features. It also adds a GitHub Actions workflow. -- Running `npx checkly pw-test` will use the `playwright.config.ts` file and run the test suite in Checkly. +``` +. +├── README.md +├── .github +│ └── workflow.yml +├── src +│ ├── __checks__ +│ │ ├── synthetics +│ │ │ ├── 01-api.check.js +│ │ │ ├── 02-business-critical.check.js +│ │ │ ├── 03-browse-and-search.spec.js +│ │ │ ├── 04-add-to-cart.spec.js +│ │ │ ├── 05-multi-step-api.spec.js +│ │ │ └── 06-multi-step-api.check.js +│ │ ├── uptime +│ │ │ ├── heartbeat.check.js +│ │ │ ├── tcp.check.js +│ │ │ └── url.check.js +│ │ └── utils +│ │ ├── alert-channels.js +│ │ ├── auth-client.js +│ │ ├── setup.js +│ │ └── website-groups.check.js +│ └── tests +│ ├── login.setup.js +│ └── webshop-interactions.spec.js +├── checkly.config.js +├── playwright.config.js +├── package.json +└── package-lock.json +``` + +- Running `npx checkly pw-test` will use the `playwright.config.js` file and run the test suite in Checkly. - Running `npx checkly test` will look for `.check.js` files and `.spec.js` in `__checks__` directories and execute them in a dry run. @@ -53,5 +84,5 @@ npm install --save-dev @playwright/test@1.54.1 ## Questions? -Check [our CLI docs](https://www.checklyhq.com/docs/cli/), the [main Checkly docs](https://checklyhq.com/docs) or +Check [the Checkly CLI docs](https://www.checklyhq.com/docs/cli/), the [main Checkly docs](https://checklyhq.com/docs) or join our [Slack community](https://checklyhq.com/slack). diff --git a/examples/advanced-project-js/checkly.config.js b/examples/advanced-project-js/checkly.config.js index 1a428c806..16ca06adc 100644 --- a/examples/advanced-project-js/checkly.config.js +++ b/examples/advanced-project-js/checkly.config.js @@ -1,5 +1,5 @@ -const { defineConfig } = require('checkly'); -const { RetryStrategyBuilder } = require('checkly/constructs'); +const { defineConfig } = require('checkly') +const { AlertEscalationBuilder, RetryStrategyBuilder } = require('checkly/constructs') /** * See https://www.checklyhq.com/docs/cli/project-structure/ @@ -27,9 +27,10 @@ const config = defineConfig({ runtimeId: '2025.04', /* Failed check runs will be retried before triggering alerts */ retryStrategy: RetryStrategyBuilder.fixedStrategy({ baseBackoffSeconds: 60, maxRetries: 4, sameRegion: true }), + alertEscalationPolicy: AlertEscalationBuilder.runBasedEscalation(1), /* A glob pattern that matches the Checks inside your repo, see https://www.checklyhq.com/docs/cli/using-check-test-match/ */ checkMatch: '**/__checks__/**/*.check.js', - /* Global configuration option for Playwright-powered checks. See https://www.checklyhq.com/docs/browser-checks/playwright-test/#global-configuration */ + /* Global configuration option for Browser and Multistep checks. See https://www.checklyhq.com/docs/browser-checks/playwright-test/#global-configuration */ playwrightConfig: { timeout: 30000, use: { @@ -39,10 +40,11 @@ const config = defineConfig({ }, browserChecks: { /* A glob pattern matches any Playwright .spec.js files and automagically creates a Browser Check. This way, you - * can just write native Playwright code. See https://www.checklyhq.com/docs/cli/using-check-test-match/ + * can just write Playwright code. See https://www.checklyhq.com/docs/constructs/including-checks/#browserchecks-testmatch * */ testMatch: '**/__checks__/**/*.spec.js', }, + // Playwright Check Suites definition, run the whole Playwright Test Suite in a Check playwrightConfigPath: './playwright.config.js', playwrightChecks: [ { @@ -60,6 +62,6 @@ const config = defineConfig({ /* How many times to retry a failing test run when running `npx checkly test` or `npx checkly trigger` (max. 3) */ retries: 0, }, -}); +}) -module.exports = config; +module.exports = config diff --git a/examples/advanced-project-js/package.json b/examples/advanced-project-js/package.json index 68e6e8d1b..6522287e4 100644 --- a/examples/advanced-project-js/package.json +++ b/examples/advanced-project-js/package.json @@ -12,6 +12,7 @@ "devDependencies": { "@playwright/test": "^1", "checkly": "latest", - "jiti": "^1" + "jiti": "^2", + "dotenv": "^16.0.0" } } diff --git a/examples/advanced-project-js/playwright.config.js b/examples/advanced-project-js/playwright.config.js index 032678b7b..f9bf95afe 100644 --- a/examples/advanced-project-js/playwright.config.js +++ b/examples/advanced-project-js/playwright.config.js @@ -1,18 +1,30 @@ -const { defineConfig, devices } = require('@playwright/test'); -const path = require('path'); +const { defineConfig, devices } = require('@playwright/test') -const AUTH_FILE = '.auth/user.json'; +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +const dotenv = require('dotenv') +const path = require('path') +dotenv.config({ path: path.resolve(__dirname, '.env') }) -const config = defineConfig({ +const AUTH_FILE = '.auth/user.json' + +/** + * See https://playwright.dev/docs/test-configuration. + */ + +module.exports = defineConfig({ timeout: 30000, use: { baseURL: 'https://www.danube-web.shop', viewport: { width: 1280, height: 720 }, + trace: 'on', }, projects: [ { name: 'login-setup', - testMatch: /.*\.setup.ts/, + testMatch: /.*\.setup.js/, use: { ...devices['Desktop Chrome'], }, @@ -24,7 +36,7 @@ const config = defineConfig({ ...devices['Desktop Firefox'], storageState: path.resolve(__dirname, AUTH_FILE), }, - dependencies: ["login-setup"], + dependencies: ['login-setup'], }, { name: 'Chromium', @@ -38,6 +50,4 @@ const config = defineConfig({ dependencies: ['login-setup'], }, ] -}); - -module.exports = config; +}) diff --git a/examples/advanced-project-js/src/__checks__/api.check.js b/examples/advanced-project-js/src/__checks__/api.check.js deleted file mode 100644 index e4e49238b..000000000 --- a/examples/advanced-project-js/src/__checks__/api.check.js +++ /dev/null @@ -1,24 +0,0 @@ -const path = require('path'); -const { ApiCheck, AssertionBuilder } = require('checkly/constructs'); -const { websiteGroup } = require('./website-group.check'); - -new ApiCheck('books-api-check-1', { - name: 'Books API', - group: websiteGroup, - degradedResponseTime: 10000, - maxResponseTime: 20000, - setupScript: { - entrypoint: path.join(__dirname, './utils/setup.js'), - }, - request: { - url: 'https://danube-web.shop/api/books', - method: 'GET', - followRedirects: true, - skipSSL: false, - assertions: [ - AssertionBuilder.statusCode().equals(200), - AssertionBuilder.jsonBody('$[0].id').isNotNull(), - ], - }, - runParallel: true, -}); diff --git a/examples/advanced-project-js/src/__checks__/heartbeat.check.js b/examples/advanced-project-js/src/__checks__/heartbeat.check.js deleted file mode 100644 index 5fb6fddbe..000000000 --- a/examples/advanced-project-js/src/__checks__/heartbeat.check.js +++ /dev/null @@ -1,16 +0,0 @@ -const { HeartbeatMonitor } = require('checkly/constructs') - -// Heartbeat monitors allow you to monitor jobs or recurring tasks. -// This feature is only available on paid plans. -// Upgrade your plan to start using it https://app.checklyhq.com/new-billing -// If you're already on a paid plan, uncomment the following lines to create a heartbeat monitor. - -/* new HeartbeatMonitor('heartbeat-1', { - name: 'Send weekly newsletter job', - period: 1, - periodUnit: 'hours', - grace: 30, - graceUnit: 'minutes', -}) - */ - diff --git a/examples/advanced-project-js/src/__checks__/home.check.js b/examples/advanced-project-js/src/__checks__/home.check.js deleted file mode 100644 index 4100fdea3..000000000 --- a/examples/advanced-project-js/src/__checks__/home.check.js +++ /dev/null @@ -1,33 +0,0 @@ -const path = require('path'); -const { BrowserCheck } = require('checkly/constructs'); -const { smsChannel, emailChannel } = require('../alert-channels'); -const { websiteGroup } = require('./website-group.check'); - -const alertChannels = [smsChannel, emailChannel]; - -/* - * In this example, we bundle all basic checks needed to check the Checkly homepage. We explicitly define the Browser - * check here, instead of using a default based on a .spec.js file. This allows us to override the check configuration. - * We can also add more checks into one file, in this case to cover a specific API call needed to hydrate the homepage. - */ - -// We can define multiple checks in a single *.check.js file. -new BrowserCheck('homepage-browser-check', { - name: 'Home page', - alertChannels, - group: websiteGroup, - code: { - entrypoint: path.join(__dirname, 'homepage.spec.js'), - }, - runParallel: true, -}); - -new BrowserCheck('login-browser-check', { - name: 'Login Check', - alertChannels, - group: websiteGroup, - code: { - entrypoint: path.join(__dirname, 'login.spec.js'), - }, - runParallel: true, -}); diff --git a/examples/advanced-project-js/src/__checks__/homepage.spec.js b/examples/advanced-project-js/src/__checks__/homepage.spec.js deleted file mode 100644 index 668ca71a4..000000000 --- a/examples/advanced-project-js/src/__checks__/homepage.spec.js +++ /dev/null @@ -1,9 +0,0 @@ -const { test, expect } = require('@playwright/test'); - -test('webshop homepage', async ({ page }) => { - const response = await page.goto(''); - - expect(response?.status()).toBeLessThan(400); - await expect(page).toHaveTitle(/Danube WebShop/); - await page.screenshot({ path: 'homepage.jpg' }); -}); diff --git a/examples/advanced-project-js/src/__checks__/login.spec.js b/examples/advanced-project-js/src/__checks__/login.spec.js deleted file mode 100644 index a45fc0fce..000000000 --- a/examples/advanced-project-js/src/__checks__/login.spec.js +++ /dev/null @@ -1,15 +0,0 @@ -const { test } = require('@playwright/test'); - -test('login', async ({ page }) => { - // navigate to our target web page - await page.goto(''); - - // click on the login button and go through the login procedure - await page.click('#login'); - await page.type('#n-email', 'user@email.com'); - await page.type('#n-password2', 'supersecure1'); - await page.click('#goto-signin-btn'); - - // wait until the login confirmation message is shown - await page.waitForSelector('#login-message', { visible: true }); -}); diff --git a/examples/advanced-project-js/src/__checks__/multi-step-spacex.check.js b/examples/advanced-project-js/src/__checks__/multi-step-spacex.check.js deleted file mode 100644 index c980b40ec..000000000 --- a/examples/advanced-project-js/src/__checks__/multi-step-spacex.check.js +++ /dev/null @@ -1,22 +0,0 @@ -const path = require('path') -const { MultiStepCheck } = require('checkly/constructs') -const { smsChannel, emailChannel } = require('../alert-channels') - -const alertChannels = [smsChannel, emailChannel] - -/* -* In this example, we utilize the SpaceX public API to construct a series of chained requests, with the goal of confirming -* that the capsules retrieved from the main endpoint match those obtained from the individual capsule endpoint. -* Read more in our documentation https://www.checklyhq.com/docs/multistep-checks/ -*/ - -// We can define multiple checks in a single *.check.js file. -new MultiStepCheck('spacex-multistep-check', { - name: 'SpaceX MS', - runtimeId: '2024.09', - alertChannels, - code: { - entrypoint: path.join(__dirname, 'spacex-requests.spec.js') - }, - runParallel: true, -}) diff --git a/examples/advanced-project-js/src/__checks__/synthetics/01-api.check.js b/examples/advanced-project-js/src/__checks__/synthetics/01-api.check.js new file mode 100644 index 000000000..a9c7c2181 --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/01-api.check.js @@ -0,0 +1,30 @@ +const path = require('path') +const { ApiCheck, AssertionBuilder } = require('checkly/constructs') +const { syntheticGroup } = require('../utils/website-groups.check') + +// API checks send an HTTP request to a URL endpoint and validate the response. Read more at: +// https://www.checklyhq.com/docs/api-checks/ + +new ApiCheck('books-api-check-1', { + name: 'Books API', + degradedResponseTime: 10000, // milliseconds + maxResponseTime: 20000, + setupScript: { + // API checks can run arbitrary JS/TS code before or after a check. + entrypoint: path.join(__dirname, '../utils/setup.js') + }, + group: syntheticGroup, + request: { + url: 'https://danube-web.shop/api/books', + method: 'GET', + followRedirects: true, + skipSSL: false, + assertions: [ + AssertionBuilder.statusCode().equals(200), + AssertionBuilder.headers('content-type').equals('application/json; charset=utf-8'), + AssertionBuilder.jsonBody('$[0].id').isNotNull(), + AssertionBuilder.jsonBody('$[0].author').equals('Fric Eromm'), + ], + }, + runParallel: true, +}) diff --git a/examples/advanced-project-js/src/__checks__/synthetics/02-business-critical.check.js b/examples/advanced-project-js/src/__checks__/synthetics/02-business-critical.check.js new file mode 100644 index 000000000..31682576d --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/02-business-critical.check.js @@ -0,0 +1,25 @@ +const path = require('path') +const { BrowserCheck } = require('checkly/constructs') +const { syntheticGroup } = require('../utils/website-groups.check') + +// Configures two checks for our homepage in a single configuration file. +// Most settings for these checks are defined in the check group, +// in /utils/website-groups.check.ts + +new BrowserCheck('browse-and-search-check', { + name: 'Browse and search', + group: syntheticGroup, + code: { + entrypoint: path.join(__dirname, '03-browse-and-search.spec.js') + }, + runParallel: true, +}) + +new BrowserCheck('login-browser-check', { + name: 'Add to cart flow', + group: syntheticGroup, + code: { + entrypoint: path.join(__dirname, '04-add-to-cart.spec.js') + }, + runParallel: true, +}) diff --git a/examples/advanced-project-js/src/__checks__/synthetics/03-browse-and-search.spec.js b/examples/advanced-project-js/src/__checks__/synthetics/03-browse-and-search.spec.js new file mode 100644 index 000000000..e9c5b7ff4 --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/03-browse-and-search.spec.js @@ -0,0 +1,22 @@ +const { test, expect } = require('@playwright/test') + +// Source code for a browser check using Playwright Test. Find more Playwright information at +// https://www.checklyhq.com/learn/playwright/ + +// This environment variable is set in the group configuration in /utils/website-groups.check.ts +const searchString = process.env.AUTHOR_NAME || "Herman Moulson" + +test('Browse and search for a book', async ({ page }) => { + // The baseURL can be set in the playwrightConfig of your Checkly config + await page.goto('/') + await expect(page.getByRole('heading', { name: 'SPECIAL OFFER: 20% OFF BOOKS' })).toBeVisible() + + // Navigate to Fantasy category and verify a book is visible + await page.locator('a', { hasText: 'Fantasy' }).click() + await expect(page.getByText('The Pickled Lynx')).toBeVisible() + + // Use the search bar to search for an author and verify a book is visible + await page.getByRole('textbox').fill(searchString) + await page.getByRole('button', { name: 'Search' }).click() + await expect(page.getByText('Haben oder haben')).toBeVisible() +}) diff --git a/examples/advanced-project-js/src/__checks__/synthetics/04-add-to-cart.spec.js b/examples/advanced-project-js/src/__checks__/synthetics/04-add-to-cart.spec.js new file mode 100644 index 000000000..e4670ff6d --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/04-add-to-cart.spec.js @@ -0,0 +1,26 @@ +const { test, expect } = require('@playwright/test') + +// This check tests the add to cart functionality, a critical flow for e-commerce sites + +test('Add to cart', async ({ page }) => { + // The baseURL can be set in the playwrightConfig of your Checkly config + await page.goto('/') + + // Navigate to a book category + await page.locator('a', { hasText: 'Horror' }).click() + + // Add first book to cart + await page.locator('.preview').first().click() + await page.getByRole('button', { name: 'Add to cart' }).click() + + // Redirected to cart preview, verify item is added + await expect(page.getByText('Your Shopping Cart')).toBeVisible() + + // Verify cart page and item is present + const cartItems = await page.getByRole('listitem') + await expect(cartItems).toHaveCount(1) + + // Verify cart total is displayed + await expect(page.getByText('Total')).toBeVisible() + await expect(page.getByRole('button', { name: 'Checkout' })).toBeVisible() +}) diff --git a/examples/advanced-project-js/src/__checks__/spacex-requests.spec.js b/examples/advanced-project-js/src/__checks__/synthetics/05-multi-step-api.spec.js similarity index 55% rename from examples/advanced-project-js/src/__checks__/spacex-requests.spec.js rename to examples/advanced-project-js/src/__checks__/synthetics/05-multi-step-api.spec.js index f329fcc95..6bc0325c9 100644 --- a/examples/advanced-project-js/src/__checks__/spacex-requests.spec.js +++ b/examples/advanced-project-js/src/__checks__/synthetics/05-multi-step-api.spec.js @@ -1,12 +1,13 @@ -import { test, expect } from '@playwright/test' +const { test, expect } = require('@playwright/test') + +// Multistep checks let you make multiple API calls in sequence. Rather than +// a simple API check configuration, multistep checks use Playwright allowing +// chained API requests. Read more at: https://www.checklyhq.com/docs/multistep-checks/ const baseUrl = 'https://api.spacexdata.com/v3' -test('space-x dragon capsules', async ({ request }) => { - /** - * Get all SpaceX Dragon Capsules - */ - const [first] = await test.step('get all capsules', async () => { +test('space-x capsules', async ({ request }) => { + const [first] = await test.step('get all Dragon capsules', async () => { const response = await request.get(`${baseUrl}/dragons`) expect(response).toBeOK() @@ -16,9 +17,6 @@ test('space-x dragon capsules', async ({ request }) => { return data }) - /** - * Get a single Dragon Capsule - */ await test.step('get single dragon capsule', async () => { const response = await request.get(`${baseUrl}/dragons/${first.id}`) expect(response).toBeOK() diff --git a/examples/advanced-project-js/src/__checks__/synthetics/06-multi-step-api.check.js b/examples/advanced-project-js/src/__checks__/synthetics/06-multi-step-api.check.js new file mode 100644 index 000000000..a159f3f1f --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/06-multi-step-api.check.js @@ -0,0 +1,13 @@ +const path = require('path') +const { MultiStepCheck, Frequency } = require('checkly/constructs') +const { syntheticGroup } = require('../utils/website-groups.check') + +new MultiStepCheck('multistep-check-1', { + name: 'Multistep API check', + group: syntheticGroup, + frequency: Frequency.EVERY_1H, + locations: ['us-east-1', 'eu-west-1'], + code: { + entrypoint: path.join(__dirname, '05-multi-step-api.spec.js') + }, +}) diff --git a/examples/advanced-project-js/src/__checks__/uptime/heartbeat.check.js b/examples/advanced-project-js/src/__checks__/uptime/heartbeat.check.js new file mode 100644 index 000000000..f2bdfa7f3 --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/uptime/heartbeat.check.js @@ -0,0 +1,17 @@ +const { HeartbeatMonitor } = require('checkly/constructs') + +// Heartbeat monitors allow you to monitor jobs or recurring tasks. +// After you deploy this check, you'll get a ping URL for your check +// from the Checkly CLI. This check will generate alerts if it's not +// getting pings at the generated URL, so it's deactivated for now. +// Further documentation: https://www.checklyhq.com/docs/heartbeat-monitors/ + +new HeartbeatMonitor('heartbeat-1', { + name: 'Send weekly newsletter job', + activated: false, + period: 1, + periodUnit: 'hours', + grace: 30, + graceUnit: 'minutes', +}) + \ No newline at end of file diff --git a/examples/advanced-project-js/src/__checks__/uptime/tcp.check.js b/examples/advanced-project-js/src/__checks__/uptime/tcp.check.js new file mode 100644 index 000000000..c041252db --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/uptime/tcp.check.js @@ -0,0 +1,23 @@ +const { TcpMonitor, TcpAssertionBuilder } = require('checkly/constructs') +const { uptimeGroup } = require('../utils/website-groups.check') + +// TCP monitors check if a TCP connection to a given host and port can be established. +// They’re useful for monitoring databases, message queues, or any service that doesn’t use HTTP. +// Read more: https://www.checklyhq.com/docs/tcp-monitors/ + +new TcpMonitor('hello-tcp-1', { + name: 'TCPbin Monitor', + activated: true, + group: uptimeGroup, + maxResponseTime: 5000, // milliseconds + degradedResponseTime: 4000, + request: { + hostname: 'tcpbin.com', + port: 4242, + data: 'ping\n', + ipFamily: 'IPv6', + assertions: [ + TcpAssertionBuilder.responseData().contains('ping') + ] + } +}) diff --git a/examples/advanced-project-js/src/__checks__/uptime/url.check.js b/examples/advanced-project-js/src/__checks__/uptime/url.check.js new file mode 100644 index 000000000..585e77982 --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/uptime/url.check.js @@ -0,0 +1,52 @@ +const { UrlAssertionBuilder, UrlMonitor } = require('checkly/constructs') +const { uptimeGroup } = require('../utils/website-groups.check') + +// URL Monitors are the simplest and most efficient uptime monitors, they only +// check for the status code of the response. +// Further documentation: https://www.checklyhq.com/docs/url-monitors/ + +new UrlMonitor('homepage-url-check', { + name: 'Homepage URL Monitor', + activated: true, + group: uptimeGroup, + maxResponseTime: 10000, // milliseconds + degradedResponseTime: 5000, + request: { + url: 'https://www.danube-web.shop/', + followRedirects: true, + assertions: [ + UrlAssertionBuilder.statusCode().equals(200), + ] + } +}) + +// In this extension example, we create multiple URL monitors at once + +// Here we're using a short array of URLS, but this example can be extended +// by parsing a sitemap or JSON file and adding every URL to an array. +const sitemapUrls = [ + 'https://danube-web.shop/books/2', + 'https://danube-web.shop/category?string=economics' +] + +sitemapUrls.forEach((url, index) => { + // Create paths and friendly names for each monitor + const urlPath = new URL(url).pathname.replace(/\//g, '-').replace(/^-+|-+$/g, '') || 'root' + const monitorId = `checkly-${urlPath}` + const monitorName = `${urlPath.replace(/-/g, ' ')} URL monitor` + + // Create each monitor + new UrlMonitor(monitorId, { + name: monitorName, + activated: true, + group: uptimeGroup, // We'll want to use a group to manage configuration + request: { + url: url, + skipSSL: false, + followRedirects: true, + assertions: [ + UrlAssertionBuilder.statusCode().equals(200), + ] + } + }) +}) diff --git a/examples/advanced-project-js/src/__checks__/url.check.js b/examples/advanced-project-js/src/__checks__/url.check.js deleted file mode 100644 index 60658ac98..000000000 --- a/examples/advanced-project-js/src/__checks__/url.check.js +++ /dev/null @@ -1,15 +0,0 @@ -const { UrlAssertionBuilder, UrlMonitor } = require('checkly/constructs') - -new UrlMonitor('books-url-check', { - name: 'Books URL', - activated: true, - maxResponseTime: 10000, - degradedResponseTime: 5000, - request: { - url: 'https://www.danube-web.shop/', - followRedirects: true, - assertions: [ - UrlAssertionBuilder.statusCode().equals(200), - ] - } -}) diff --git a/examples/advanced-project-js/src/alert-channels.js b/examples/advanced-project-js/src/__checks__/utils/alert-channels.js similarity index 75% rename from examples/advanced-project-js/src/alert-channels.js rename to examples/advanced-project-js/src/__checks__/utils/alert-channels.js index 2fcc6a527..e87f53ff2 100644 --- a/examples/advanced-project-js/src/alert-channels.js +++ b/examples/advanced-project-js/src/__checks__/utils/alert-channels.js @@ -1,11 +1,17 @@ -const { URL } = require('node:url'); +const { URL } = require('node:url') const { SmsAlertChannel, EmailAlertChannel, SlackAlertChannel, WebhookAlertChannel, -} = require('checkly/constructs'); +} = require('checkly/constructs') + +// Defines the settings for our alert channels. +// Not every channel is used in the rest of this demo project. +// Note that you can create multiple channels of a type: +// e.g. "prodEmailChannel" "frontendTeamEmailChannel" etc. +// See all the options at https://www.checklyhq.com/docs/alerting-and-retries/alert-channels/ const sendDefaults = { sendFailure: true, @@ -18,12 +24,12 @@ const sendDefaults = { const smsChannel = new SmsAlertChannel('sms-channel-1', { phoneNumber: '0031061234567890', ...sendDefaults, -}); +}) const emailChannel = new EmailAlertChannel('email-channel-1', { address: 'alerts@acme.com', ...sendDefaults, -}); +}) const slackChannel = new SlackAlertChannel('slack-channel-1', { url: new URL( @@ -31,7 +37,7 @@ const slackChannel = new SlackAlertChannel('slack-channel-1', { ), channel: '#ops', ...sendDefaults, -}); +}) const webhookChannel = new WebhookAlertChannel('webhook-channel-1', { name: 'Pushover webhook', @@ -48,11 +54,11 @@ const webhookChannel = new WebhookAlertChannel('webhook-channel-1', { "message":"{{ALERT_TYPE}} {{STARTED_AT}} ({{RESPONSE_TIME}}ms) {{RESULT_LINK}}" }`, ...sendDefaults, -}); +}) module.exports = { smsChannel, emailChannel, slackChannel, webhookChannel, -}; +} diff --git a/examples/advanced-project-js/src/__checks__/utils/auth-client.js b/examples/advanced-project-js/src/__checks__/utils/auth-client.js index b6cf0ef0a..fee0a3a25 100644 --- a/examples/advanced-project-js/src/__checks__/utils/auth-client.js +++ b/examples/advanced-project-js/src/__checks__/utils/auth-client.js @@ -1,5 +1,10 @@ -export async function getToken() { - console.log('Fetching a token from an imaginary auth API endpoint'); - const token = await new Promise((resolve) => resolve('123abc')); - return token; +// This auth client is a stub of the script you'd want to run to retrieve an +// auth token. Read more about authentication in API monitors here: https://www.checklyhq.com/docs/detect/synthetic-monitoring/api-checks/examples/#user-authentication-apis + +async function getToken() { + console.log('Fetching a token from an imaginary auth API endpoint') + const token = await new Promise((resolve) => resolve('123abc')) + return token } + +module.exports = { getToken } diff --git a/examples/advanced-project-js/src/__checks__/utils/setup.js b/examples/advanced-project-js/src/__checks__/utils/setup.js index 236efdf69..03ff84ae8 100644 --- a/examples/advanced-project-js/src/__checks__/utils/setup.js +++ b/examples/advanced-project-js/src/__checks__/utils/setup.js @@ -4,14 +4,14 @@ * This setup script example shows how you can import other files, use async functions and instrument the globals * that are available during runtime, such as the request. * - * For more info see: https://www.checklyhq.com/docs/api-checks/setup-teardown-scripts/#setup-scripts + * For more info see: https://www.checklyhq.com/docs/detect/synthetic-monitoring/api-checks/set-up-and-tear-down/#setup-scripts */ -const { getToken } = require('./auth-client'); +const { getToken } = require('./auth-client') async function setup() { - const token = await getToken(); - request.headers['X-My-Auth-Header'] = token; + const token = await getToken() + request.headers['X-My-Auth-Header'] = token } -setup(); +setup() diff --git a/examples/advanced-project-js/src/__checks__/utils/website-groups.check.js b/examples/advanced-project-js/src/__checks__/utils/website-groups.check.js new file mode 100644 index 000000000..ec0ea13da --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/utils/website-groups.check.js @@ -0,0 +1,37 @@ +const { CheckGroupV2, Frequency, AlertEscalationBuilder } = require('checkly/constructs') +const { smsChannel, emailChannel } = require('./alert-channels') + +// This file defines two groups, one for synthetics monitors and one for uptime +// monitors. Read more about group configuration at: https://www.checklyhq.com/docs/groups/ + +const syntheticGroup = new CheckGroupV2('check-group-synthetics', { + name: 'Synthetic Monitors Group', + activated: true, + muted: false, + frequency: Frequency.EVERY_15M, + locations: ['us-east-1', 'eu-west-1'], + tags: ['synthetics'], + // By setting an alertEscalationPolicy, these settings will override those on individual checks + alertEscalationPolicy: AlertEscalationBuilder.runBasedEscalation( + 2, // Alert after 2 consecutive failures + { amount: 2, interval: 5 }, // Send 2 reminders, 5 minutes apart + { enabled: true, percentage: 50 } // Alert if 50% of parallel runs fail + ), + alertChannels: [emailChannel, smsChannel], + environmentVariables: [{ key: 'AUTHOR_NAME', value: 'Fric Eromm' }], + concurrency: 10 +}) + +const uptimeGroup = new CheckGroupV2('check-group-uptime', { + name: 'Uptime Monitors Group', + muted: false, + frequency: Frequency.EVERY_15M, + tags: ['uptime'], + concurrency: 10 +}) + + +module.exports = { + syntheticGroup, + uptimeGroup, +} diff --git a/examples/advanced-project-js/src/__checks__/website-group.check.js b/examples/advanced-project-js/src/__checks__/website-group.check.js deleted file mode 100644 index 784bac09f..000000000 --- a/examples/advanced-project-js/src/__checks__/website-group.check.js +++ /dev/null @@ -1,35 +0,0 @@ -const { CheckGroup, RetryStrategyBuilder } = require('checkly/constructs'); -const { smsChannel, emailChannel } = require('../alert-channels'); -const alertChannels = [smsChannel, emailChannel]; -/* - * In this example, we bundle checks using a Check Group. We add checks to this group in two ways: - * 1. By passing the `CheckGroup` object for the `group` property of the check. - * 2. By defining a glob pattern like `*.spec.js` that matches Browser Checks , just like at the Project level, e.g. - * - * browserChecks: { - * testMatch: './*.spec.js' - * } - * - * You can use either or both. In this example we show option 1. - **/ - -const websiteGroup = new CheckGroup('website-check-group-1', { - name: 'Website Group', - activated: true, - muted: false, - runtimeId: '2024.09', - locations: ['us-east-1', 'eu-west-1'], - tags: ['mac', 'group'], - environmentVariables: [], - apiCheckDefaults: {}, - concurrency: 100, - alertChannels, - /* - * Failed check runs in this group will be retried before triggering alerts. - * The wait time between retries will increase linearly: 30 seconds, 60 seconds, and then 90 seconds between the retries. - */ - retryStrategy: RetryStrategyBuilder.linearStrategy({ baseBackoffSeconds: 30, maxRetries: 3, sameRegion: false }), - runParallel: true, -}); - -module.exports = { websiteGroup }; diff --git a/examples/advanced-project-js/src/tests/homepage.spec.js b/examples/advanced-project-js/src/tests/homepage.spec.js deleted file mode 100644 index aea2f38a6..000000000 --- a/examples/advanced-project-js/src/tests/homepage.spec.js +++ /dev/null @@ -1,9 +0,0 @@ -const { test, expect } = require('@playwright/test'); - -test('webshop homepage @homepage', async ({ page }) => { - const response = await page.goto(''); - - expect(response?.status()).toBeLessThan(400); - await expect(page).toHaveTitle(/Danube WebShop/); - await page.screenshot({ path: 'homepage.jpg' }); -}); \ No newline at end of file diff --git a/examples/advanced-project-js/src/tests/login.setup.js b/examples/advanced-project-js/src/tests/login.setup.js new file mode 100644 index 000000000..9f9641297 --- /dev/null +++ b/examples/advanced-project-js/src/tests/login.setup.js @@ -0,0 +1,31 @@ +const { test: setup } = require('@playwright/test') + +const AUTH_FILE = ".auth/user.json" + +// This check logs in as a user would, by clicking and entering text on your web page. + +// See Checkly's documentation on secrets and variables: https://www.checklyhq.com/docs/platform/variables/ +const password = process.env.WEB_SHOP_PASSWORD || 'defaultPwd' + +setup('Log into web shop', async ({ page }) => { + // The base URL is set in your Playwright config + await page.goto('/') + + await page.getByRole('button', { name: 'Log in' }).click() + + await page.getByPlaceholder('Email').click() + await page.getByPlaceholder('Email').fill('testUser@email.com') + + await page.getByPlaceholder('Password').click() + await page.getByPlaceholder('Password').fill(password) + + // await page.getByRole('button', { name: 'Sign in' }).click() + + // Use storage state to write the browser state to disk + // More info: https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state + await page.context().storageState({ path: AUTH_FILE }) + console.log(`Wrote storage state to ${AUTH_FILE}`) + + // Once login is successful to your site, add assertions to check the response + // await expect(page.getByText('Welcome back')).toBeVisible() +}) diff --git a/examples/advanced-project-js/src/tests/login.spec.js b/examples/advanced-project-js/src/tests/login.spec.js deleted file mode 100644 index 0ed49f542..000000000 --- a/examples/advanced-project-js/src/tests/login.spec.js +++ /dev/null @@ -1,17 +0,0 @@ -const { test } = require('@playwright/test'); - -test('login', { - tag: '@login', -}, async ({ page }) => { - // navigate to our target web page - await page.goto(''); - - // click on the login button and go through the login procedure - await page.click('#login'); - await page.type('#n-email', 'user@email.com'); - await page.type('#n-password2', 'supersecure1'); - await page.click('#goto-signin-btn'); - - // wait until the login confirmation message is shown - await page.waitForSelector('#login-message', { visible: true }); -}); \ No newline at end of file diff --git a/examples/advanced-project-js/src/tests/webshop-interactions.spec.js b/examples/advanced-project-js/src/tests/webshop-interactions.spec.js new file mode 100644 index 000000000..ec61a5bc3 --- /dev/null +++ b/examples/advanced-project-js/src/tests/webshop-interactions.spec.js @@ -0,0 +1,28 @@ +const { test, expect } = require('@playwright/test') + +// This test is part of a Playwright Check Suite, configured in playwright.config.js + +// This test validates the homepage with interactive navigation and user flows +test.describe('Homepage navigation and interactions', () => { + test.beforeEach(async ({ page }) => { + // The baseURL is configured in playwright.config.js + await page.goto('/') + }) + + test('Homepage loads with special offer banner', async ({ page }) => { + await expect(page.getByRole('heading', { name: 'SPECIAL OFFER: 20% OFF BOOKS' })).toBeVisible() + }) + + test('Sidebar navigation works', async ({ page }) => { + await page.locator('a', { hasText: 'Horror' }).click() + await expect(page.getByText('The Sitting')).toBeVisible() + }) + + test('Search bar is interactive', async ({ page }) => { + // Fill in search bar + await page.getByRole('textbox').fill('Laughterhouse-Five') + + // Wait for search results to appear + await expect(page.getByText('Truk Tugennov')).toBeVisible() + }) +}) diff --git a/examples/advanced-project/README.md b/examples/advanced-project/README.md index f0b6ef145..15bc906c0 100644 --- a/examples/advanced-project/README.md +++ b/examples/advanced-project/README.md @@ -1,7 +1,6 @@ # Checkly Monitoring-as-code: Advanced Project -This example project shows how you can use the Checkly CLI in a monitoring as code (MaC) workflow. We are using the -https://checklyhq.com website as a monitoring target. +This example project shows how you can use the Checkly CLI in a monitoring as code (MaC) workflow. 1. Write API Checks and Playwright-powered Browser Checks or fully native Playwright Check Suites. 2. Add Alert Channels, and dry-run your Checks on 20+ global locations. @@ -15,7 +14,40 @@ npm create checkly@latest -- --template advanced-project This project has examples of all Checkly check types and showcases some advanced features. It also adds a GitHub Actions workflow. +``` +. +├── README.md +├── .github +│ └── workflow.yml +├── src +│ ├── __checks__ +│ │ ├── synthetics +│ │ │ ├── 01-api.check.ts +│ │ │ ├── 02-business-critical.check.ts +│ │ │ ├── 03-browse-and-search.spec.ts +│ │ │ ├── 04-add-to-cart.spec.ts +│ │ │ ├── 05-multi-step-api.spec.ts +│ │ │ └── 06-multi-step-api.check.ts +│ │ ├── uptime +│ │ │ ├── heartbeat.check.ts +│ │ │ ├── tcp.check.ts +│ │ │ └── url.check.ts +│ │ └── utils +│ │ ├── alert-channels.ts +│ │ ├── auth-client.ts +│ │ ├── setup.ts +│ │ └── website-groups.check.ts +│ └── tests +│ ├── login.setup.ts +│ └── webshop-interactions.spec.ts +├── checkly.config.ts +├── playwright.config.ts +├── package.json +└── package-lock.json +``` + - Running `npx checkly pw-test` will use the `playwright.config.ts` file and run the test suite in Checkly. + - Running `npx checkly test` will look for `.check.ts` files and `.spec.ts` in `__checks__` directories and execute them in a dry run. - Running `npx checkly deploy` will deploy your checks to Checkly, attach alert channels, and run them on a 10m schedule in the @@ -52,5 +84,5 @@ npm install --save-dev @playwright/test@1.54.1 ## Questions? -Check [the CLI docs](https://www.checklyhq.com/docs/cli/), the [main Checkly docs](https://checklyhq.com/docs) or +Check [the Checkly CLI docs](https://www.checklyhq.com/docs/cli/), the [main Checkly docs](https://checklyhq.com/docs) or join our [Slack community](https://checklyhq.com/slack). diff --git a/examples/advanced-project/checkly.config.ts b/examples/advanced-project/checkly.config.ts index 2d37f729a..061d25860 100644 --- a/examples/advanced-project/checkly.config.ts +++ b/examples/advanced-project/checkly.config.ts @@ -31,21 +31,20 @@ const config = defineConfig({ alertEscalationPolicy: AlertEscalationBuilder.runBasedEscalation(1), /* A glob pattern that matches the Checks inside your repo, see https://www.checklyhq.com/docs/cli/using-check-test-match/ */ checkMatch: '**/__checks__/**/*.check.ts', - /* Global configuration option for Playwright-powered checks. See https://www.checklyhq.com/docs/browser-checks/playwright-test/#global-configuration */ + /* Global configuration option for Browser and Multistep checks. See https://www.checklyhq.com/docs/browser-checks/playwright-test/#global-configuration */ playwrightConfig: { timeout: 30000, use: { - baseURL: "https://www.checklyhq.com", + baseURL: 'https://www.danube-web.shop', viewport: { width: 1280, height: 720 }, }, }, browserChecks: { /* A glob pattern matches any Playwright .spec.ts files and automagically creates a Browser Check. This way, you - * can just write native Playwright code. See https://www.checklyhq.com/docs/cli/using-check-test-match/ - * */ + * can just write Playwright code. See https://www.checklyhq.com/docs/constructs/including-checks/#browserchecks-testmatch + * */ testMatch: '**/__checks__/**/*.spec.ts', }, - // Playwright Check Suites definition, run the whole Playwright Test Suite in a Check playwrightConfigPath: './playwright.config.ts', playwrightChecks: [ diff --git a/examples/advanced-project/package.json b/examples/advanced-project/package.json index e0c9b7e13..6522287e4 100644 --- a/examples/advanced-project/package.json +++ b/examples/advanced-project/package.json @@ -12,6 +12,7 @@ "devDependencies": { "@playwright/test": "^1", "checkly": "latest", - "jiti": "^2" + "jiti": "^2", + "dotenv": "^16.0.0" } } diff --git a/examples/advanced-project/playwright.config.ts b/examples/advanced-project/playwright.config.ts index b4f1804a8..c034fe84c 100644 --- a/examples/advanced-project/playwright.config.ts +++ b/examples/advanced-project/playwright.config.ts @@ -1,14 +1,14 @@ -import { defineConfig, devices } from "@playwright/test" +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") }) +import dotenv from 'dotenv' +import path from 'path' +dotenv.config({ path: path.resolve(__dirname, '.env') }) -export const AUTH_FILE = ".auth/user.json" +export const AUTH_FILE = '.auth/user.json' /** * See https://playwright.dev/docs/test-configuration. @@ -17,9 +17,9 @@ export const AUTH_FILE = ".auth/user.json" export default defineConfig({ timeout: 30000, use: { - baseURL: "https://www.checklyhq.com", + baseURL: 'https://www.danube-web.shop', viewport: { width: 1280, height: 720 }, - trace: "on", + trace: 'on', }, projects: [ { @@ -36,7 +36,7 @@ export default defineConfig({ ...devices['Desktop Firefox'], storageState: path.resolve(__dirname, AUTH_FILE), }, - dependencies: ["login-setup"], + dependencies: ['login-setup'], }, { name: 'Chromium', @@ -47,7 +47,7 @@ export default defineConfig({ // Optionally add Checkly user-agent userAgent: `${devices['Desktop Chrome'].userAgent} (Checkly, https://www.checklyhq.com)`, }, - dependencies: ["login-setup"], + dependencies: ['login-setup'], }, ] -}); +}) diff --git a/examples/advanced-project/src/__checks__/synthetics/02-business-critical.check.ts b/examples/advanced-project/src/__checks__/synthetics/02-business-critical.check.ts index c51abab9d..121ade566 100644 --- a/examples/advanced-project/src/__checks__/synthetics/02-business-critical.check.ts +++ b/examples/advanced-project/src/__checks__/synthetics/02-business-critical.check.ts @@ -7,7 +7,7 @@ import { syntheticGroup } from '../utils/website-groups.check' // in /utils/website-groups.check.ts new BrowserCheck('browse-and-search-check', { - name: 'Browse and Search', + name: 'Browse and search', group: syntheticGroup, code: { entrypoint: path.join(__dirname, '03-browse-and-search.spec.ts') @@ -16,10 +16,10 @@ new BrowserCheck('browse-and-search-check', { }) new BrowserCheck('login-browser-check', { - name: 'Login', + name: 'Add to cart flow', group: syntheticGroup, code: { - entrypoint: path.join(__dirname, '04-login.spec.ts') + entrypoint: path.join(__dirname, '04-add-to-cart.spec.ts') }, runParallel: true, }) diff --git a/examples/advanced-project/src/__checks__/synthetics/03-browse-and-search.spec.ts b/examples/advanced-project/src/__checks__/synthetics/03-browse-and-search.spec.ts index 1390dfd14..f9b704eb3 100644 --- a/examples/advanced-project/src/__checks__/synthetics/03-browse-and-search.spec.ts +++ b/examples/advanced-project/src/__checks__/synthetics/03-browse-and-search.spec.ts @@ -4,15 +4,19 @@ import { test, expect } from '@playwright/test' // https://www.checklyhq.com/learn/playwright/ // This environment variable is set in the group configuration in /utils/website-groups.check.ts -const searchString: string = process.env.authorName || "Herman Moulson" +const searchString: string = process.env.AUTHOR_NAME || "Herman Moulson" -test('webshop homepage', async ({ page }) => { - await page.goto('http://danube-web.shop/'); - await expect(page.getByRole('heading', { name: 'SPECIAL OFFER: 20% OFF BOOKS' })).toBeVisible(); - await page.locator('a').filter({ hasText: 'Fantasy' }).click(); - await expect(page.getByText('The Pickled Lynx')).toBeVisible(); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill(searchString); - await page.getByRole('button', { name: 'Search' }).click(); - await expect(page.getByText('Haben oder haben')).toBeVisible(); +test('Browse and search for a book', async ({ page }) => { + // The baseURL can be set in the playwrightConfig of your Checkly config + await page.goto('/') + await expect(page.getByRole('heading', { name: 'SPECIAL OFFER: 20% OFF BOOKS' })).toBeVisible() + + // Navigate to Fantasy category and verify a book is visible + await page.locator('a', { hasText: 'Fantasy' }).click() + await expect(page.getByText('The Pickled Lynx')).toBeVisible() + + // Use the search bar to search for an author and verify a book is visible + await page.getByRole('textbox').fill(searchString) + await page.getByRole('button', { name: 'Search' }).click() + await expect(page.getByText('Haben oder haben')).toBeVisible() }) diff --git a/examples/advanced-project/src/__checks__/synthetics/04-add-to-cart.spec.ts b/examples/advanced-project/src/__checks__/synthetics/04-add-to-cart.spec.ts new file mode 100644 index 000000000..b479a3220 --- /dev/null +++ b/examples/advanced-project/src/__checks__/synthetics/04-add-to-cart.spec.ts @@ -0,0 +1,26 @@ +import { test, expect } from '@playwright/test' + +// This check tests the add to cart functionality, a critical flow for e-commerce sites + +test('Add to cart', async ({ page }) => { + // The baseURL can be set in the playwrightConfig of your Checkly config + await page.goto('/') + + // Navigate to a book category + await page.locator('a', { hasText: 'Horror' }).click() + + // Add first book to cart + await page.locator('.preview').first().click() + await page.getByRole('button', { name: 'Add to cart' }).click() + + // Redirected to cart preview, verify item is added + await expect(page.getByText('Your Shopping Cart')).toBeVisible() + + // Verify cart page and item is present + const cartItems = await page.getByRole('listitem') + await expect(cartItems).toHaveCount(1) + + // Verify cart total is displayed + await expect(page.getByText('Total')).toBeVisible() + await expect(page.getByRole('button', { name: 'Checkout' })).toBeVisible() +}) diff --git a/examples/advanced-project/src/__checks__/synthetics/04-login.spec.ts b/examples/advanced-project/src/__checks__/synthetics/04-login.spec.ts deleted file mode 100644 index 0f4165ee4..000000000 --- a/examples/advanced-project/src/__checks__/synthetics/04-login.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { test } from '@playwright/test' - -// This check logs in as a user would, by clicking and entering text on your web page. - -test('login', async ({ page }) => { - // See Checkly's documentation on secrets and variables: https://www.checklyhq.com/docs/browser-checks/variables/ - const password = process.env.WEB_SHOP_PASSWORD || 'defaultPwd'; - await page.goto('http://danube-web.shop/'); - await page.getByRole('button', { name: 'Log in' }).click(); - await page.getByRole('textbox', { name: 'Email' }).click(); - await page.getByRole('textbox', { name: 'Email' }).fill('testUser@email.com'); - await page.getByRole('textbox', { name: 'Password' }).click(); - await page.getByRole('textbox', { name: 'Password' }).fill(password); - await page.getByRole('button', { name: 'Sign In' }).click(); - // Once login is successful to your site, add assertions to check the response -}) diff --git a/examples/advanced-project/src/__checks__/synthetics/05-multi-step-api.spec.ts b/examples/advanced-project/src/__checks__/synthetics/05-multi-step-api.spec.ts index 006e0979d..33c490811 100644 --- a/examples/advanced-project/src/__checks__/synthetics/05-multi-step-api.spec.ts +++ b/examples/advanced-project/src/__checks__/synthetics/05-multi-step-api.spec.ts @@ -4,11 +4,9 @@ import { test, expect } from '@playwright/test' // a simple API check configuration, multistep checks use Playwright allowing // chained API requests. Read more at: https://www.checklyhq.com/docs/multistep-checks/ - const baseUrl = 'https://api.spacexdata.com/v3' test('space-x capsules', async ({ request }) => { - const [first] = await test.step('get all Dragon capsules', async () => { const response = await request.get(`${baseUrl}/dragons`) expect(response).toBeOK() diff --git a/examples/advanced-project/src/__checks__/synthetics/06-multi-step-api.check.ts b/examples/advanced-project/src/__checks__/synthetics/06-multi-step-api.check.ts index c95f71a91..e123e10dc 100644 --- a/examples/advanced-project/src/__checks__/synthetics/06-multi-step-api.check.ts +++ b/examples/advanced-project/src/__checks__/synthetics/06-multi-step-api.check.ts @@ -1,8 +1,10 @@ import { MultiStepCheck, Frequency } from 'checkly/constructs' import * as path from 'path' +import { syntheticGroup } from '../utils/website-groups.check' new MultiStepCheck('multistep-check-1', { name: 'Multistep API check', + group: syntheticGroup, frequency: Frequency.EVERY_1H, locations: ['us-east-1', 'eu-west-1'], code: { diff --git a/examples/advanced-project/src/__checks__/uptime/heartbeat.check.ts b/examples/advanced-project/src/__checks__/uptime/heartbeat.check.ts index 1b69a9457..a9bc205f4 100644 --- a/examples/advanced-project/src/__checks__/uptime/heartbeat.check.ts +++ b/examples/advanced-project/src/__checks__/uptime/heartbeat.check.ts @@ -6,13 +6,9 @@ import { HeartbeatMonitor } from 'checkly/constructs' // getting pings at the generated URL, so it's deactivated for now. // Further documentation: https://www.checklyhq.com/docs/heartbeat-monitors/ -// This feature is only available on paid plans. -// Upgrade your plan to start using it https://app.checklyhq.com/new-billing - - new HeartbeatMonitor('heartbeat-1', { - activated: false, name: 'Send weekly newsletter job', + activated: false, period: 1, periodUnit: 'hours', grace: 30, diff --git a/examples/advanced-project/src/__checks__/uptime/url.check.ts b/examples/advanced-project/src/__checks__/uptime/url.check.ts index b2cf592a3..1c302c0df 100644 --- a/examples/advanced-project/src/__checks__/uptime/url.check.ts +++ b/examples/advanced-project/src/__checks__/uptime/url.check.ts @@ -1,7 +1,6 @@ import { UrlAssertionBuilder, UrlMonitor } from 'checkly/constructs' import { uptimeGroup } from '../utils/website-groups.check' - // URL Monitors are the simplest and most efficient uptime monitors, they only // check for the status code of the response. // Further documentation: https://www.checklyhq.com/docs/url-monitors/ diff --git a/examples/advanced-project/src/__checks__/utils/auth-client.ts b/examples/advanced-project/src/__checks__/utils/auth-client.ts index 82f7dd3ff..994f94488 100644 --- a/examples/advanced-project/src/__checks__/utils/auth-client.ts +++ b/examples/advanced-project/src/__checks__/utils/auth-client.ts @@ -1,5 +1,5 @@ // This auth client is a stub of the script you'd want to run to retrieve an -// auth token. Read more about authentication in API monitors here: https://www.checklyhq.com/docs/api-checks/setup-script-examples/ +// auth token. Read more about authentication in API monitors here: https://www.checklyhq.com/docs/detect/synthetic-monitoring/api-checks/examples/#user-authentication-apis export async function getToken (): Promise { console.log('Fetching a token from an imaginary auth API endpoint') diff --git a/examples/advanced-project/src/__checks__/utils/setup.ts b/examples/advanced-project/src/__checks__/utils/setup.ts index 9f0a84ae6..1b4c79c79 100644 --- a/examples/advanced-project/src/__checks__/utils/setup.ts +++ b/examples/advanced-project/src/__checks__/utils/setup.ts @@ -2,7 +2,7 @@ import { getToken } from './auth-client' // This setup script example shows how you can import other files, use async // functions and instrument the globals that are available during runtime, such as the request. -// For more info see: https://www.checklyhq.com/docs/api-checks/setup-teardown-scripts/#setup-scripts +// For more info see: https://www.checklyhq.com/docs/detect/synthetic-monitoring/api-checks/set-up-and-tear-down/#setup-scripts async function setup () { const token = await getToken() diff --git a/examples/advanced-project/src/__checks__/utils/website-groups.check.ts b/examples/advanced-project/src/__checks__/utils/website-groups.check.ts index db33774da..318ed92d0 100644 --- a/examples/advanced-project/src/__checks__/utils/website-groups.check.ts +++ b/examples/advanced-project/src/__checks__/utils/website-groups.check.ts @@ -18,7 +18,7 @@ export const syntheticGroup = new CheckGroupV2('check-group-synthetics', { { enabled: true, percentage: 50 } // Alert if 50% of parallel runs fail ), alertChannels: [emailChannel, smsChannel], - environmentVariables: [{ key: 'authorName', value: 'Fric Eromm' }], + environmentVariables: [{ key: 'AUTHOR_NAME', value: 'Fric Eromm' }], concurrency: 10 }) diff --git a/examples/advanced-project/src/tests/homepage.spec.ts b/examples/advanced-project/src/tests/homepage.spec.ts deleted file mode 100644 index efd8c1c28..000000000 --- a/examples/advanced-project/src/tests/homepage.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { expect, test } from "@playwright/test" - -test("Visit Checkly home page", async ({ page }) => { - await page.goto("/") - - await expect(page).toHaveTitle(/Checkly/) - - // More test code ... -}) \ No newline at end of file diff --git a/examples/advanced-project/src/tests/login.setup.ts b/examples/advanced-project/src/tests/login.setup.ts index 3a53ae72e..1c4707597 100644 --- a/examples/advanced-project/src/tests/login.setup.ts +++ b/examples/advanced-project/src/tests/login.setup.ts @@ -1,15 +1,31 @@ -import { test as setup } from "@playwright/test" +import { test as setup } from '@playwright/test' -const AUTH_FILE = ".auth/user.json" +// This check logs in as a user would, by clicking and entering text on your web page. -setup("Log into Checkly", async ({ page }) => { - await page.goto("/") +// See Checkly's documentation on secrets and variables: https://www.checklyhq.com/docs/browser-checks/variables/ +const password: string = process.env.WEB_SHOP_PASSWORD || 'defaultPwd' - // Perform your login actions which will set cookies and localstorage entries - // ... +const AUTH_FILE = '.auth/user.json' +setup('Log into web shop', async ({ page }) => { + // The base URL is set in your Playwright config + await page.goto('/') + + await page.getByRole('button', { name: 'Log in' }).click() + + await page.getByPlaceholder('Email').click() + await page.getByPlaceholder('Email').fill('testUser@email.com') + + await page.getByPlaceholder('Password').click() + await page.getByPlaceholder('Password').fill(password) + + // await page.getByRole('button', { name: 'Sign in' }).click() + // Use storage state to write the browser state to disk - // More info: https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state + // More info: https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state await page.context().storageState({ path: AUTH_FILE }) console.log(`Wrote storage state to ${AUTH_FILE}`) + + // Once login is successful to your site, add assertions to check the response + // await expect(page.getByText('Welcome back')).toBeVisible() }) diff --git a/examples/advanced-project/src/tests/webshop-interactions.spec.ts b/examples/advanced-project/src/tests/webshop-interactions.spec.ts new file mode 100644 index 000000000..2192d0c6f --- /dev/null +++ b/examples/advanced-project/src/tests/webshop-interactions.spec.ts @@ -0,0 +1,28 @@ +import { expect, test } from '@playwright/test' + +// This test is part of a Playwright Check Suite, configured in playwright.config.ts + +// This test validates the homepage with interactive navigation and user flows +test.describe('Homepage navigation and interactions', () => { + test.beforeEach(async ({ page }) => { + // The baseURL is configured in playwright.config.ts + await page.goto('/') + }) + + test('Homepage loads with special offer banner', async ({ page }) => { + await expect(page.getByRole('heading', { name: 'SPECIAL OFFER: 20% OFF BOOKS' })).toBeVisible() + }) + + test('Sidebar navigation works', async ({ page }) => { + await page.locator('a', { hasText: 'Horror' }).click() + await expect(page.getByText('The Sitting')).toBeVisible() + }) + + test('Search bar is interactive', async ({ page }) => { + // Fill in search bar + await page.getByRole('textbox').fill('Laughterhouse-Five') + + // Wait for search results to appear + await expect(page.getByText('Truk Tugennov')).toBeVisible() + }) +}) diff --git a/examples/boilerplate-project-js/.gitignore b/examples/boilerplate-project-js/.gitignore deleted file mode 100644 index 3c3629e64..000000000 --- a/examples/boilerplate-project-js/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/examples/boilerplate-project-js/README.md b/examples/boilerplate-project-js/README.md index 19a654c17..22cea013d 100644 --- a/examples/boilerplate-project-js/README.md +++ b/examples/boilerplate-project-js/README.md @@ -1,13 +1,12 @@ # Checkly Monitoring-as-code: Boilerplate Project -This example project shows how you can use the Checkly CLI in a monitoring as code (MaC) workflow. We are using the -https://checklyhq.com website as a monitoring target. +This example project shows how you can use the Checkly CLI in a monitoring as code (MaC) workflow. -1. Write API Checks and Playwright-powered Browser Checks! +1. Write API Checks and Playwright-powered Browser Checks or fully native Playwright Check Suites. 2. Test -> Deploy: now you have your app monitored around the clock. All from your code base. ``` -npm create checkly@latest -- --template boilerplate-project +npm create checkly@latest -- --template boilerplate-project-js ``` ## Project Structure @@ -18,25 +17,30 @@ This project has the basic boilerplate files needed to get you started. . ├── README.md ├── __checks__ -│   ├── api.check.js -│   └── homepage.spec.js +│ ├── api.check.js +│ ├── heartbeat.check.js +│ ├── homepage.js +│ └── url.check.js ├── tests -│   ├── docspage.spec.js -│   └── landingpage.spec.js +│ └── webshop-interactions.spec.js ├── checkly.config.js -└── package.json +├── playwright.config.js +├── package.json +└── package-lock.json ``` -- Running `npx checkly pw-test` will use the `playwright.config.ts` file and run the test suite in Checkly. -- +- Running `npx checkly pw-test` will use the `playwright.config.js` file and run the test suite in Checkly. + - Running `npx checkly test` will look for `.check.js` files and `.spec.js` in `__checks__` directories and execute them in a dry run. -- Running `npx checkly deploy` will deploy your checks to Checkly, attach alert channels, and run them on a 10m schedule in the +- Running `npx checkly test --record` will run all checks in a test session for you to preview in the UI. + +- Running `npx checkly deploy` will deploy your checks to Checkly, attach alert channels, and run them on a 10m schedule in the region `us-east-1` and `eu-west-1` ## CLI Commands -Run the core CLI commands with `npx checkly ` +Run the core CLI commands with `npx checkly ` | Command | Action | |:---------------------|:-------------------------------------------------| @@ -50,7 +54,7 @@ Run the core CLI commands with `npx checkly ` ## Adding and running `@playwright/test` -Run `npm install` to install all required dependencies. +Run `npm install` to install all required dependencies. `@playwright/test` will give you full code completion and run `.spec.js` files for local debugging. @@ -62,5 +66,5 @@ npm install --save-dev @playwright/test@1.54.1 ## Questions? -Check [our CLI docs](https://www.checklyhq.com/docs/cli/), the [main Checkly docs](https://checklyhq.com/docs) or +Check [the Checkly CLI docs](https://www.checklyhq.com/docs/cli/), the [main Checkly docs](https://checklyhq.com/docs) or join our [Slack community](https://checklyhq.com/slack). diff --git a/examples/boilerplate-project-js/__checks__/api.check.js b/examples/boilerplate-project-js/__checks__/api.check.js index 1f3991022..4c66734f1 100644 --- a/examples/boilerplate-project-js/__checks__/api.check.js +++ b/examples/boilerplate-project-js/__checks__/api.check.js @@ -1,9 +1,12 @@ const { ApiCheck, AssertionBuilder } = require("checkly/constructs"); +// API checks send an HTTP request to a URL endpoint and validate the response. Read more at: +// https://www.checklyhq.com/docs/api-checks/ + new ApiCheck("books-api-check-1", { name: "Books API", alertChannels: [], - degradedResponseTime: 10000, + degradedResponseTime: 10000, // milliseconds maxResponseTime: 20000, request: { url: "https://danube-web.shop/api/books", @@ -16,4 +19,4 @@ new ApiCheck("books-api-check-1", { ], }, runParallel: true, -}); +}) diff --git a/examples/boilerplate-project-js/__checks__/heartbeat.check.js b/examples/boilerplate-project-js/__checks__/heartbeat.check.js index 5fb6fddbe..1cd149642 100644 --- a/examples/boilerplate-project-js/__checks__/heartbeat.check.js +++ b/examples/boilerplate-project-js/__checks__/heartbeat.check.js @@ -1,16 +1,16 @@ const { HeartbeatMonitor } = require('checkly/constructs') // Heartbeat monitors allow you to monitor jobs or recurring tasks. -// This feature is only available on paid plans. -// Upgrade your plan to start using it https://app.checklyhq.com/new-billing -// If you're already on a paid plan, uncomment the following lines to create a heartbeat monitor. +// After you deploy this check, you'll get a ping URL for your check +// from the Checkly CLI. This check will generate alerts if it's not +// getting pings at the generated URL, so it's deactivated for now. +// Further documentation: https://www.checklyhq.com/docs/heartbeat-monitors/ -/* new HeartbeatMonitor('heartbeat-1', { +new HeartbeatMonitor('heartbeat-1', { name: 'Send weekly newsletter job', + activated: false, period: 1, periodUnit: 'hours', grace: 30, graceUnit: 'minutes', }) - */ - diff --git a/examples/boilerplate-project-js/__checks__/homepage.spec.js b/examples/boilerplate-project-js/__checks__/homepage.spec.js index 109d301a1..ca7cce72e 100644 --- a/examples/boilerplate-project-js/__checks__/homepage.spec.js +++ b/examples/boilerplate-project-js/__checks__/homepage.spec.js @@ -1,11 +1,12 @@ -const { test, expect } = require('@playwright/test'); +const { test, expect } = require('@playwright/test') -// You can override the default Playwright test timeout of 30s -// test.setTimeout(60_000); +// This test is being used as a Browser check +// See browserCheck.testMatch in your checkly.config.js to configure -test('webshop homepage', async ({ page }) => { - const response = await page.goto('https://danube-web.shop'); - expect(response?.status()).toBeLessThan(400); - await expect(page).toHaveTitle(/Danube WebShop/); - await page.screenshot({ path: 'homepage.jpg' }); -}); +test('Visit webshop homepage', async ({ page }) => { + // The baseURL for Browser checks can be set in the playwrightConfig of your checkly.config.js + const response = await page.goto('/') + expect(response?.status()).toBeLessThan(400) + await expect(page).toHaveTitle(/Danube WebShop/) + await page.screenshot({ path: 'homepage.jpg' }) +}) diff --git a/examples/boilerplate-project-js/checkly.config.js b/examples/boilerplate-project-js/checkly.config.js index 000558d61..96a8c623e 100644 --- a/examples/boilerplate-project-js/checkly.config.js +++ b/examples/boilerplate-project-js/checkly.config.js @@ -1,4 +1,4 @@ -const { defineConfig } = require('checkly'); +const { defineConfig } = require('checkly') /** * See https://www.checklyhq.com/docs/cli/project-structure/ @@ -26,16 +26,17 @@ const config = defineConfig({ runtimeId: '2025.04', /* A glob pattern that matches the Checks inside your repo, see https://www.checklyhq.com/docs/cli/using-check-test-match/ */ checkMatch: '**/__checks__/**/*.check.js', - /* Global configuration option for Playwright-powered checks. See https://www.checklyhq.com/docs/browser-checks/playwright-test/#global-configuration */ + /* Global configuration option for Browser and Multistep checks. See https://www.checklyhq.com/docs/browser-checks/playwright-test/#global-configuration */ playwrightConfig: { + timeout: 30000, use: { - baseURL: "https://www.checklyhq.com", + baseURL: 'https://www.danube-web.shop', viewport: { width: 1280, height: 720 }, - }, + } }, browserChecks: { /* A glob pattern matches any Playwright .spec.js files and automagically creates a Browser Check. This way, you - * can just write native Playwright code. See https://www.checklyhq.com/docs/cli/using-check-test-match/ + * can just write Playwright code. See https://www.checklyhq.com/docs/constructs/including-checks/#browserchecks-testmatch * */ testMatch: '**/__checks__/**/*.spec.js', }, @@ -59,4 +60,4 @@ const config = defineConfig({ }, }) -module.exports = config; +module.exports = config diff --git a/examples/boilerplate-project-js/package.json b/examples/boilerplate-project-js/package.json index 35eea0b6e..a8f6eb3e8 100644 --- a/examples/boilerplate-project-js/package.json +++ b/examples/boilerplate-project-js/package.json @@ -10,6 +10,9 @@ "author": "", "license": "ISC", "devDependencies": { - "checkly": "latest" + "@playwright/test": "^1", + "checkly": "latest", + "jiti": "^2", + "dotenv": "^16.0.0" } } diff --git a/examples/boilerplate-project-js/playwright.config.js b/examples/boilerplate-project-js/playwright.config.js index 4ea8d9c3e..a5de2cd50 100644 --- a/examples/boilerplate-project-js/playwright.config.js +++ b/examples/boilerplate-project-js/playwright.config.js @@ -1,8 +1,8 @@ -const { defineConfig, devices } = require('@playwright/test'); +const { defineConfig, devices } = require('@playwright/test') module.exports = defineConfig({ timeout: 30000, - // Look for test files in the "tests" directory, relative to this configuration file. + // Look for test files in the 'tests' directory, relative to this configuration file. testDir: './tests', // Run all tests in parallel. @@ -22,11 +22,12 @@ module.exports = defineConfig({ use: { // Base URL to use in actions like `await page.goto('/')`. - baseURL: "https://www.checklyhq.com", + baseURL: 'https://www.danube-web.shop', viewport: { width: 1280, height: 720 }, // Always collect trace trace: 'on', }, + // Configure projects for major browsers. projects: [ { @@ -39,4 +40,4 @@ module.exports = defineConfig({ }, ], -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/examples/boilerplate-project-js/tests/docspage.spec.js b/examples/boilerplate-project-js/tests/docspage.spec.js deleted file mode 100644 index a3f0559ee..000000000 --- a/examples/boilerplate-project-js/tests/docspage.spec.js +++ /dev/null @@ -1,9 +0,0 @@ -import { expect, test } from "@playwright/test" - -test("Visit Checkly home page", async ({ page }) => { - await page.goto("/docs") - - await expect(page).toHaveTitle(/Checkly/) - - // More test code ... -}) diff --git a/examples/boilerplate-project-js/tests/landingpage.spec.js b/examples/boilerplate-project-js/tests/landingpage.spec.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/boilerplate-project-js/tests/webshop-interactions.spec.js b/examples/boilerplate-project-js/tests/webshop-interactions.spec.js new file mode 100644 index 000000000..ec61a5bc3 --- /dev/null +++ b/examples/boilerplate-project-js/tests/webshop-interactions.spec.js @@ -0,0 +1,28 @@ +const { test, expect } = require('@playwright/test') + +// This test is part of a Playwright Check Suite, configured in playwright.config.js + +// This test validates the homepage with interactive navigation and user flows +test.describe('Homepage navigation and interactions', () => { + test.beforeEach(async ({ page }) => { + // The baseURL is configured in playwright.config.js + await page.goto('/') + }) + + test('Homepage loads with special offer banner', async ({ page }) => { + await expect(page.getByRole('heading', { name: 'SPECIAL OFFER: 20% OFF BOOKS' })).toBeVisible() + }) + + test('Sidebar navigation works', async ({ page }) => { + await page.locator('a', { hasText: 'Horror' }).click() + await expect(page.getByText('The Sitting')).toBeVisible() + }) + + test('Search bar is interactive', async ({ page }) => { + // Fill in search bar + await page.getByRole('textbox').fill('Laughterhouse-Five') + + // Wait for search results to appear + await expect(page.getByText('Truk Tugennov')).toBeVisible() + }) +}) diff --git a/examples/boilerplate-project/README.md b/examples/boilerplate-project/README.md index 2acabd0dd..c2d171e29 100644 --- a/examples/boilerplate-project/README.md +++ b/examples/boilerplate-project/README.md @@ -1,9 +1,8 @@ # Checkly Monitoring-as-code: Boilerplate Project -This example project shows how you can use the Checkly CLI in a monitoring as code (MaC) workflow. We are using the -https://checklyhq.com website as a monitoring target. +This example project shows how you can use the Checkly CLI in a monitoring as code (MaC) workflow. -1. Write API Checks and Playwright-powered Browser Checks! +1. Write API Checks and Playwright-powered Browser Checks or fully native Playwright Check Suites. 2. Test -> Deploy: now you have your app monitored around the clock. All from your code base. ``` @@ -18,13 +17,14 @@ This project has the basic boilerplate files needed to get you started. . ├── README.md ├── __checks__ -│   ├── api.check.ts -│   └── homepage.spec.ts +│ ├── api.check.ts +│ ├── heartbeat.check.ts +│ ├── homepage.spec.ts +│ └── url.check.ts ├── tests -│   ├── docspage.spec.ts -│   └── landingpage.spec.ts -├── checkly.config.ts +│ └── webshop-interactions.spec.ts ├── checkly.config.ts +├── playwright.config.ts ├── package.json └── package-lock.json ``` @@ -34,12 +34,12 @@ This project has the basic boilerplate files needed to get you started. - Running `npx checkly test --record` will run all checks in a test session for you to preview in the UI. -- Running `npx checkly deploy` will deploy your checks to Checkly, attach alert channels, and run them on a 10m schedule in the +- Running `npx checkly deploy` will deploy your checks to Checkly, attach alert channels, and run them on a 10m schedule in the region `us-east-1` and `eu-west-1` ## CLI Commands -Run the core CLI commands with `npx checkly ` +Run the core CLI commands with `npx checkly ` | Command | Action | |:---------------------|:-------------------------------------------------| @@ -53,7 +53,7 @@ Run the core CLI commands with `npx checkly ` ## Adding and running `@playwright/test` -Run `npm install` to install all required dependencies. +Run `npm install` to install all required dependencies. `@playwright/test` will give you full code completion and run `.spec.js` files for local debugging. @@ -65,5 +65,5 @@ npm install --save-dev @playwright/test@1.54.1 ## Questions? -Check [our CLI docs](https://www.checklyhq.com/docs/cli/), the [main Checkly docs](https://checklyhq.com/docs) or +Check [the Checkly CLI docs](https://www.checklyhq.com/docs/cli/), the [main Checkly docs](https://checklyhq.com/docs) or join our [Slack community](https://checklyhq.com/slack). diff --git a/examples/boilerplate-project/__checks__/api.check.ts b/examples/boilerplate-project/__checks__/api.check.ts index 626c42f5e..1e4954cef 100644 --- a/examples/boilerplate-project/__checks__/api.check.ts +++ b/examples/boilerplate-project/__checks__/api.check.ts @@ -1,9 +1,12 @@ import { ApiCheck, AssertionBuilder } from 'checkly/constructs' +// API checks send an HTTP request to a URL endpoint and validate the response. Read more at: +// https://www.checklyhq.com/docs/api-checks/ + new ApiCheck('books-api-check-1', { name: 'Books API', alertChannels: [], - degradedResponseTime: 10000, + degradedResponseTime: 10000, // milliseconds maxResponseTime: 20000, request: { url: 'https://danube-web.shop/api/books', diff --git a/examples/boilerplate-project/__checks__/heartbeat.check.ts b/examples/boilerplate-project/__checks__/heartbeat.check.ts index 410498dbe..8db2b4959 100644 --- a/examples/boilerplate-project/__checks__/heartbeat.check.ts +++ b/examples/boilerplate-project/__checks__/heartbeat.check.ts @@ -1,16 +1,16 @@ import { HeartbeatMonitor } from 'checkly/constructs' // Heartbeat monitors allow you to monitor jobs or recurring tasks. -// This feature is only available on paid plans. -// Upgrade your plan to start using it https://app.checklyhq.com/new-billing -// If you're already on a paid plan, uncomment the following lines to create a heartbeat monitor. +// After you deploy this check, you'll get a ping URL for your check +// from the Checkly CLI. This check will generate alerts if it's not +// getting pings at the generated URL, so it's deactivated for now. +// Further documentation: https://www.checklyhq.com/docs/heartbeat-monitors/ -/* new HeartbeatMonitor('heartbeat-1', { +new HeartbeatMonitor('heartbeat-1', { name: 'Send weekly newsletter job', + activated: false, period: 1, periodUnit: 'hours', grace: 30, graceUnit: 'minutes', -}) - */ - + }) diff --git a/examples/boilerplate-project/__checks__/homepage.spec.ts b/examples/boilerplate-project/__checks__/homepage.spec.ts index 73e7df9a9..630d3397c 100644 --- a/examples/boilerplate-project/__checks__/homepage.spec.ts +++ b/examples/boilerplate-project/__checks__/homepage.spec.ts @@ -1,10 +1,11 @@ import { test, expect } from '@playwright/test' -// You can override the default Playwright test timeout of 30s -// test.setTimeout(60_000); +// This test is being used as a Browser check +// See browserCheck.testMatch in your checkly.config.ts to configure -test('webshop homepage', async ({ page }) => { - const response = await page.goto('https://danube-web.shop') +test('Visit webshop homepage', async ({ page }) => { + // The baseURL for Browser checks can be set in the playwrightConfig of your checkly.config.ts + const response = await page.goto('/') expect(response?.status()).toBeLessThan(400) await expect(page).toHaveTitle(/Danube WebShop/) await page.screenshot({ path: 'homepage.jpg' }) diff --git a/examples/boilerplate-project/checkly.config.ts b/examples/boilerplate-project/checkly.config.ts index d6d1687ed..78f52dffb 100644 --- a/examples/boilerplate-project/checkly.config.ts +++ b/examples/boilerplate-project/checkly.config.ts @@ -26,20 +26,20 @@ const config = defineConfig({ runtimeId: '2025.04', /* A glob pattern that matches the Checks inside your repo, see https://www.checklyhq.com/docs/cli/using-check-test-match/ */ checkMatch: '**/__checks__/**/*.check.ts', - /* Global configuration option for Playwright-powered checks. See https://www.checklyhq.com/docs/browser-checks/playwright-test/#global-configuration */ + /* Global configuration option for Browser and Multistep checks. See https://www.checklyhq.com/docs/browser-checks/playwright-test/#global-configuration */ playwrightConfig: { + timeout: 30000, use: { - baseURL: "https://www.checklyhq.com", + baseURL: 'https://www.danube-web.shop', viewport: { width: 1280, height: 720 }, - }, + } }, browserChecks: { /* A glob pattern matches any Playwright .spec.ts files and automagically creates a Browser Check. This way, you - * can just write native Playwright code. See https://www.checklyhq.com/docs/cli/using-check-test-match/ + * can just write Playwright code. See https://www.checklyhq.com/docs/constructs/including-checks/#browserchecks-testmatch * */ testMatch: '**/__checks__/**/*.spec.ts', }, - // Playwright Check Suites definition, run the whole Playwright Test Suite in a Check playwrightConfigPath: './playwright.config.ts', playwrightChecks: [ diff --git a/examples/boilerplate-project/package.json b/examples/boilerplate-project/package.json index d5fa24d96..0b228c91d 100644 --- a/examples/boilerplate-project/package.json +++ b/examples/boilerplate-project/package.json @@ -12,6 +12,7 @@ "devDependencies": { "@playwright/test": "^1", "checkly": "latest", - "jiti": "^2" + "jiti": "^2", + "dotenv": "^16.0.0" } } diff --git a/examples/boilerplate-project/playwright.config.ts b/examples/boilerplate-project/playwright.config.ts index 27363045f..1a0d3e31b 100644 --- a/examples/boilerplate-project/playwright.config.ts +++ b/examples/boilerplate-project/playwright.config.ts @@ -1,8 +1,8 @@ -import { defineConfig, devices } from '@playwright/test'; +import { defineConfig, devices } from '@playwright/test' export default defineConfig({ timeout: 30000, - // Look for test files in the "tests" directory, relative to this configuration file. + // Look for test files in the 'tests' directory, relative to this configuration file. testDir: './tests', // Run all tests in parallel. @@ -22,11 +22,12 @@ export default defineConfig({ use: { // Base URL to use in actions like `await page.goto('/')`. - baseURL: "https://www.checklyhq.com", + baseURL: 'https://www.danube-web.shop', viewport: { width: 1280, height: 720 }, // Always collect trace trace: 'on', }, + // Configure projects for major browsers. projects: [ { @@ -39,4 +40,4 @@ export default defineConfig({ }, ], -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/examples/boilerplate-project/tests/docspage.spec.ts b/examples/boilerplate-project/tests/docspage.spec.ts deleted file mode 100644 index a3f0559ee..000000000 --- a/examples/boilerplate-project/tests/docspage.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { expect, test } from "@playwright/test" - -test("Visit Checkly home page", async ({ page }) => { - await page.goto("/docs") - - await expect(page).toHaveTitle(/Checkly/) - - // More test code ... -}) diff --git a/examples/boilerplate-project/tests/landingpage.spec.ts b/examples/boilerplate-project/tests/landingpage.spec.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/boilerplate-project/tests/webshop-interactions.spec.ts b/examples/boilerplate-project/tests/webshop-interactions.spec.ts new file mode 100644 index 000000000..2192d0c6f --- /dev/null +++ b/examples/boilerplate-project/tests/webshop-interactions.spec.ts @@ -0,0 +1,28 @@ +import { expect, test } from '@playwright/test' + +// This test is part of a Playwright Check Suite, configured in playwright.config.ts + +// This test validates the homepage with interactive navigation and user flows +test.describe('Homepage navigation and interactions', () => { + test.beforeEach(async ({ page }) => { + // The baseURL is configured in playwright.config.ts + await page.goto('/') + }) + + test('Homepage loads with special offer banner', async ({ page }) => { + await expect(page.getByRole('heading', { name: 'SPECIAL OFFER: 20% OFF BOOKS' })).toBeVisible() + }) + + test('Sidebar navigation works', async ({ page }) => { + await page.locator('a', { hasText: 'Horror' }).click() + await expect(page.getByText('The Sitting')).toBeVisible() + }) + + test('Search bar is interactive', async ({ page }) => { + // Fill in search bar + await page.getByRole('textbox').fill('Laughterhouse-Five') + + // Wait for search results to appear + await expect(page.getByText('Truk Tugennov')).toBeVisible() + }) +})