From a2e18a08d42307174c29d42f1c31304a4754141b Mon Sep 17 00:00:00 2001 From: stefan judis Date: Tue, 9 Sep 2025 15:24:55 +0200 Subject: [PATCH] fix: update "advanced-js" CLI template to match the TS version --- examples/advanced-project-js/README.md | 8 +-- .../advanced-project-js/checkly.config.js | 14 +++-- .../src/__checks__/api.check.js | 24 -------- .../src/__checks__/home.check.js | 33 ----------- .../src/__checks__/homepage.spec.js | 9 --- .../src/__checks__/login.spec.js | 15 ----- .../src/__checks__/multi-step-spacex.check.js | 22 ------- .../src/__checks__/synthetics/01-api.check.js | 30 ++++++++++ .../synthetics/02-business-critical.check.js | 25 ++++++++ .../synthetics/03-browse-and-search.spec.js | 18 ++++++ .../__checks__/synthetics/04-login.spec.js | 16 +++++ .../05-multi-step-api.spec.js} | 18 +++--- .../synthetics/06-multi-step-api.check.js | 11 ++++ .../07-playwright-techniques.spec.js | 40 +++++++++++++ .../08-playwright-techniques.check.js | 19 ++++++ .../{ => uptime}/heartbeat.check.js | 12 ++-- .../src/__checks__/uptime/tcp.check.js | 23 ++++++++ .../src/__checks__/uptime/url.check.js | 53 +++++++++++++++++ .../src/__checks__/url.check.js | 15 ----- .../src/__checks__/utils/alert-channels.js | 55 ++++++++++++++++++ .../src/__checks__/utils/auth-client.js | 11 ++-- .../src/__checks__/utils/setup.js | 21 +++---- .../__checks__/utils/website-groups.check.js | 31 ++++++++++ .../src/__checks__/website-group.check.js | 35 ----------- .../advanced-project-js/src/alert-channels.js | 58 ------------------- 25 files changed, 365 insertions(+), 251 deletions(-) delete mode 100644 examples/advanced-project-js/src/__checks__/api.check.js delete mode 100644 examples/advanced-project-js/src/__checks__/home.check.js delete mode 100644 examples/advanced-project-js/src/__checks__/homepage.spec.js delete mode 100644 examples/advanced-project-js/src/__checks__/login.spec.js delete mode 100644 examples/advanced-project-js/src/__checks__/multi-step-spacex.check.js create mode 100644 examples/advanced-project-js/src/__checks__/synthetics/01-api.check.js create mode 100644 examples/advanced-project-js/src/__checks__/synthetics/02-business-critical.check.js create mode 100644 examples/advanced-project-js/src/__checks__/synthetics/03-browse-and-search.spec.js create mode 100644 examples/advanced-project-js/src/__checks__/synthetics/04-login.spec.js rename examples/advanced-project-js/src/__checks__/{spacex-requests.spec.js => synthetics/05-multi-step-api.spec.js} (55%) create mode 100644 examples/advanced-project-js/src/__checks__/synthetics/06-multi-step-api.check.js create mode 100644 examples/advanced-project-js/src/__checks__/synthetics/07-playwright-techniques.spec.js create mode 100644 examples/advanced-project-js/src/__checks__/synthetics/08-playwright-techniques.check.js rename examples/advanced-project-js/src/__checks__/{ => uptime}/heartbeat.check.js (52%) create mode 100644 examples/advanced-project-js/src/__checks__/uptime/tcp.check.js create mode 100644 examples/advanced-project-js/src/__checks__/uptime/url.check.js delete mode 100644 examples/advanced-project-js/src/__checks__/url.check.js create mode 100644 examples/advanced-project-js/src/__checks__/utils/alert-channels.js create mode 100644 examples/advanced-project-js/src/__checks__/utils/website-groups.check.js delete mode 100644 examples/advanced-project-js/src/__checks__/website-group.check.js delete mode 100644 examples/advanced-project-js/src/alert-channels.js diff --git a/examples/advanced-project-js/README.md b/examples/advanced-project-js/README.md index 5b8e021f3..30acf1da0 100644 --- a/examples/advanced-project-js/README.md +++ b/examples/advanced-project-js/README.md @@ -8,7 +8,7 @@ https://checklyhq.com website as a monitoring target. 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 @@ -17,7 +17,7 @@ This project has examples of all Checkly check types and showcases some advanced - 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 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` - An example GitHub Actions workflow is in the `.github/workflow.yml` file. It triggers all the checks in the project and deploys @@ -25,7 +25,7 @@ them if they pass. ## CLI Commands -Run the core CLI commands with `npx checkly ` +Run the core CLI commands with `npx checkly ` | Command | Action | |:---------------------|:-------------------------------------------------| @@ -47,5 +47,5 @@ npm install --save-dev @playwright/test@1.38.1 ## Questions? -Check [our CLI docs](https://www.checklyhq.com/docs/cli/), the [main Checkly docs](https://checklyhq.com/docs) or +Check [our 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 7da4b71ab..affc50e2c 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,6 +27,8 @@ const config = defineConfig({ runtimeId: '2025.04', /* Failed check runs will be retried before triggering alerts */ retryStrategy: RetryStrategyBuilder.fixedStrategy({ baseBackoffSeconds: 60, maxRetries: 4, sameRegion: true }), + /* All checks will have this alert escalation policy defined */ + 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 */ @@ -39,8 +41,8 @@ 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 native Playwright code. See https://www.checklyhq.com/docs/cli/using-check-test-match/ + * */ testMatch: '**/__checks__/**/*.spec.js', }, }, @@ -52,6 +54,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/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__/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..84dfd0f8a --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/01-api.check.js @@ -0,0 +1,30 @@ +const { join } = 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: 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..add829cbd --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/02-business-critical.check.js @@ -0,0 +1,25 @@ +const { join } = 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: join(__dirname, '03-browse-and-search.spec.js') + }, + runParallel: true, +}) + +new BrowserCheck('login-browser-check', { + name: 'Login', + group: syntheticGroup, + code: { + entrypoint: join(__dirname, '04-login.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..672ef1ebe --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/03-browse-and-search.spec.js @@ -0,0 +1,18 @@ +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.authorName || '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(); +}) diff --git a/examples/advanced-project-js/src/__checks__/synthetics/04-login.spec.js b/examples/advanced-project-js/src/__checks__/synthetics/04-login.spec.js new file mode 100644 index 000000000..963eda380 --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/04-login.spec.js @@ -0,0 +1,16 @@ +const { test } = require('@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-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..1b107b790 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,15 @@ -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 +19,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..47bdec579 --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/06-multi-step-api.check.js @@ -0,0 +1,11 @@ +const { join } = require('path') +const { MultiStepCheck, Frequency } = require('checkly/constructs') + +new MultiStepCheck('multistep-check-1', { + name: 'Multistep API check', + frequency: Frequency.EVERY_1H, + locations: ['us-east-1', 'eu-west-1'], + code: { + entrypoint: join(__dirname, '05-multi-step-api.spec.js') + }, +}) diff --git a/examples/advanced-project-js/src/__checks__/synthetics/07-playwright-techniques.spec.js b/examples/advanced-project-js/src/__checks__/synthetics/07-playwright-techniques.spec.js new file mode 100644 index 000000000..cb5c36a12 --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/07-playwright-techniques.spec.js @@ -0,0 +1,40 @@ +const { test, expect } = require('@playwright/test') +const AxeBuilder = require('@axe-core/playwright') + +// In this series of checks, we'll demonstrate some more advanced techniques +// for testing your web page with Playwright. All of these techniques can be +// used wherever you use Playwright. + +test('Book details with request interception', async ({ page }) => { + // Here we want to check the content of a book's details, but the stock + // value is dynamic. How can we stabilize it? With request interception + // read more here: https://www.checklyhq.com/learn/playwright/intercept-requests/ + await page.route('*/**/api/books/23', async route => { //wait for requests that match this pattern. + const response = await route.fetch(); + const json = await response.json(); // Capture the response JSON + json.stock = "0" // modify the JSON to have a stable value + await route.fulfill({ response, json }); // return the modified JSON + }); + await page.goto('https://danube-web.shop/books/23'); + // Removed for brevity: checks of the book's title, genre, etc. + await expect(page.getByRole('button', { name: 'Add to cart' })).toBeVisible(); + await expect(page.locator('#app-content')).toContainText("Left in stock: 0"); +}); + +test('Visual Regression Testing', async ({ page }) => { + // A visual regression check that will compare a saved screenshot to a + // current screenshot. To store an initial screenshot, run `npx checkly test --update-snapshots` + await page.goto('https://danube-web.shop/') + await expect(page).toHaveScreenshot({ maxDiffPixelRatio: 0.2 }) + await expect(page).toHaveScreenshot({ maxDiffPixels: 1000 }) + await expect(page).toHaveScreenshot({ threshold: 0.2 }) +}); + +test('Accessibility issues', async ({ page }) => { + // Uses the Axe library to perform accessibility testing on our site. + // axe-core is part of the Checkly runtime as of the 2024.02 version. + // Read more: https://www.checklyhq.com/blog/integrating-accessibility-checks-in-playwright-tes/ + await page.goto('https://danube-web.shop/'); + const accessibilityScanResults = await new AxeBuilder({ page }).analyze(); + expect(accessibilityScanResults.violations).toHaveLength(8); // ideally we'd find zero issues +}); diff --git a/examples/advanced-project-js/src/__checks__/synthetics/08-playwright-techniques.check.js b/examples/advanced-project-js/src/__checks__/synthetics/08-playwright-techniques.check.js new file mode 100644 index 000000000..a312c35d5 --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/synthetics/08-playwright-techniques.check.js @@ -0,0 +1,19 @@ +const { join } = require('path') +const { BrowserCheck } = require('checkly/constructs') +const { syntheticGroup } = require('../utils/website-groups.check') + +// Even though there are multiple test() function calls in the .spec +// file, they will all run and report as a single Checkly monitor. +// Since one of the tests compares a current screenshot to a stored one, +// this check is deactivated, until you a store a known good screenshot. +// Run `npx checkly test --update-snapshots` before activiating this check. + +new BrowserCheck('playwright-techniques', { + name: 'Playwright techniques demo', + group: syntheticGroup, + activated: false, + code: { + entrypoint: join(__dirname, '07-playwright-techniques.spec.js') + }, + runParallel: true, +}) diff --git a/examples/advanced-project-js/src/__checks__/heartbeat.check.js b/examples/advanced-project-js/src/__checks__/uptime/heartbeat.check.js similarity index 52% rename from examples/advanced-project-js/src/__checks__/heartbeat.check.js rename to examples/advanced-project-js/src/__checks__/uptime/heartbeat.check.js index 5fb6fddbe..294b879fb 100644 --- a/examples/advanced-project-js/src/__checks__/heartbeat.check.js +++ b/examples/advanced-project-js/src/__checks__/uptime/heartbeat.check.js @@ -1,16 +1,20 @@ 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/ + // 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', { + +new HeartbeatMonitor('heartbeat-1', { + activated: false, name: 'Send weekly newsletter job', period: 1, periodUnit: 'hours', grace: 30, graceUnit: 'minutes', }) - */ - 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..ed659657c --- /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..964ae2aab --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/uptime/url.check.js @@ -0,0 +1,53 @@ +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/__checks__/utils/alert-channels.js b/examples/advanced-project-js/src/__checks__/utils/alert-channels.js new file mode 100644 index 000000000..5a1312fd7 --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/utils/alert-channels.js @@ -0,0 +1,55 @@ +const { URL } = require('node:url') +const { + SmsAlertChannel, + EmailAlertChannel, + SlackAlertChannel, + WebhookAlertChannel +} = 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, + sendRecovery: true, + sendDegraded: false, + sslExpiry: true, + sslExpiryThreshold: 30 +} + +module.exports.smsChannel = new SmsAlertChannel('sms-channel-1', { + phoneNumber: '0031061234567890', + ...sendDefaults +}) + +module.exports.emailChannel = new EmailAlertChannel('email-channel-1', { + address: 'alerts@acme.com', + ...sendDefaults +}) + +module.exports.slackChannel = new SlackAlertChannel('slack-channel-1', { + url: new URL('https://hooks.slack.com/services/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'), + channel: '#ops', + ...sendDefaults +}) + +module.exports.webhookChannel = new WebhookAlertChannel('webhook-channel-1', { + name: 'Pushover webhook', + method: 'POST', + url: new URL('https://webhook.site/ddead495-8b15-4b0d-a25d-f6cda4144dc7'), + template: `{ + "token":"FILL_IN_YOUR_SECRET_TOKEN_FROM_PUSHOVER", + "user":"FILL_IN_YOUR_USER_FROM_PUSHOVER", + "title":"{{ALERT_TITLE}}", + "html":1, + "priority":2, + "retry":30, + "expire":10800, + "message":"{{ALERT_TYPE}} {{STARTED_AT}} ({{RESPONSE_TIME}}ms) {{RESULT_LINK}}" + }`, + ...sendDefaults +}) 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..c91b95118 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,8 @@ -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/api-checks/setup-script-examples/ + +export async function getToken () { + console.log('Fetching a token from an imaginary auth API endpoint') + const token = await new Promise(resolve => { return resolve('123abc') }) + return token } diff --git a/examples/advanced-project-js/src/__checks__/utils/setup.js b/examples/advanced-project-js/src/__checks__/utils/setup.js index 236efdf69..c45d6cc2a 100644 --- a/examples/advanced-project-js/src/__checks__/utils/setup.js +++ b/examples/advanced-project-js/src/__checks__/utils/setup.js @@ -1,17 +1,12 @@ -/*@global request */ +const { getToken } = require('./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 - */ +// 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 -const { getToken } = require('./auth-client'); - -async function setup() { - const token = await getToken(); - request.headers['X-My-Auth-Header'] = token; +async function setup () { + const token = await getToken() + request.headers['X-My-Auth-Header'] = token } -setup(); +await 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..05ab4c841 --- /dev/null +++ b/examples/advanced-project-js/src/__checks__/utils/website-groups.check.js @@ -0,0 +1,31 @@ +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/ + +module.exports.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: 'authorName', value: 'Fric Eromm' }], + concurrency: 10 +}) + +module.exports.uptimeGroup = new CheckGroupV2('check-group-uptime', { + name: 'Uptime Monitors Group', + muted: false, + frequency: Frequency.EVERY_15M, + tags: ['uptime'], + concurrency: 10 +}) 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/alert-channels.js b/examples/advanced-project-js/src/alert-channels.js deleted file mode 100644 index 2fcc6a527..000000000 --- a/examples/advanced-project-js/src/alert-channels.js +++ /dev/null @@ -1,58 +0,0 @@ -const { URL } = require('node:url'); - -const { - SmsAlertChannel, - EmailAlertChannel, - SlackAlertChannel, - WebhookAlertChannel, -} = require('checkly/constructs'); - -const sendDefaults = { - sendFailure: true, - sendRecovery: true, - sendDegraded: false, - sslExpiry: true, - sslExpiryThreshold: 30, -}; - -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( - 'https://hooks.slack.com/services/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' - ), - channel: '#ops', - ...sendDefaults, -}); - -const webhookChannel = new WebhookAlertChannel('webhook-channel-1', { - name: 'Pushover webhook', - method: 'POST', - url: new URL('https://webhook.site/ddead495-8b15-4b0d-a25d-f6cda4144dc7'), - template: `{ - "token":"FILL_IN_YOUR_SECRET_TOKEN_FROM_PUSHOVER", - "user":"FILL_IN_YOUR_USER_FROM_PUSHOVER", - "title":"{{ALERT_TITLE}}", - "html":1, - "priority":2, - "retry":30, - "expire":10800, - "message":"{{ALERT_TYPE}} {{STARTED_AT}} ({{RESPONSE_TIME}}ms) {{RESULT_LINK}}" - }`, - ...sendDefaults, -}); - -module.exports = { - smsChannel, - emailChannel, - slackChannel, - webhookChannel, -};