Skip to content

Commit

Permalink
Merge pull request #4056 from grafana/mergeBrowserInK6
Browse files Browse the repository at this point in the history
Merge browser in k6
  • Loading branch information
mstoykov authored Dec 13, 2024
2 parents 50251d1 + d884406 commit 745f0d4
Show file tree
Hide file tree
Showing 231 changed files with 17,567 additions and 848 deletions.
70 changes: 70 additions & 0 deletions .github/workflows/browser_e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: E2E
on:
# Enable manually triggering this workflow via the API or web UI
workflow_dispatch:
push:
branches:
- main
pull_request:
schedule:
# At 06:00 AM UTC from Monday through Friday
- cron: '0 6 * * 1-5'

defaults:
run:
shell: bash

jobs:
test:
strategy:
matrix:
go: [stable, tip]
platform: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout code
if: matrix.go != 'tip' || matrix.platform != 'windows-latest'
uses: actions/checkout@v4
- name: Install Go
if: matrix.go != 'tip' || matrix.platform != 'windows-latest'
uses: actions/setup-go@v5
with:
go-version: 1.x
- name: Install Go tip
if: matrix.go == 'tip' && matrix.platform != 'windows-latest'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release download ${{ matrix.platform }} --repo grafana/gotip --pattern 'go.zip'
unzip go.zip -d $HOME/sdk
echo "GOROOT=$HOME/sdk/gotip" >> "$GITHUB_ENV"
echo "GOPATH=$HOME/go" >> "$GITHUB_ENV"
echo "$HOME/go/bin" >> "$GITHUB_PATH"
echo "$HOME/sdk/gotip/bin" >> "$GITHUB_PATH"
- name: Build k6
if: matrix.go != 'tip' || matrix.platform != 'windows-latest'
run: |
which go
go version
go build .
./k6 version
- name: Run E2E tests
if: matrix.go != 'tip' || matrix.platform != 'windows-latest'
run: |
set -x
if [ "$RUNNER_OS" == "Linux" ]; then
export K6_BROWSER_EXECUTABLE_PATH=/usr/bin/google-chrome
fi
export K6_BROWSER_HEADLESS=true
for f in examples/browser/*.js; do
if [ "$f" == "examples/browser/hosts.js" ] && [ "$RUNNER_OS" == "Windows" ]; then
echo "skipping $f on Windows"
continue
fi
./k6 run -q "$f"
done
- name: Check screenshot
if: matrix.go != 'tip' || matrix.platform != 'windows-latest'
# TODO: Do something more sophisticated?
run: test -s screenshot.png
4 changes: 4 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ issues:
- funlen
- lll
- forcetypeassert
- path: js\/modules\/k6\/browser\/.*\.go
linters:
- revive
- contextcheck
- path: js\/modules\/k6\/html\/.*\.go
text: "exported: exported "
linters:
Expand Down
39 changes: 39 additions & 0 deletions examples/browser/colorscheme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { browser } from 'k6/browser';
import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';

export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
thresholds: {
checks: ["rate==1.0"]
}
}

export default async function() {
const context = await browser.newContext({
// valid values are "light", "dark" or "no-preference"
colorScheme: 'dark',
});
const page = await context.newPage();

try {
await page.goto(
'https://test.k6.io',
{ waitUntil: 'load' },
)
await check(page, {
'isDarkColorScheme':
p => p.evaluate(() => window.matchMedia('(prefers-color-scheme: dark)').matches)
});
} finally {
await page.close();
}
}
126 changes: 126 additions & 0 deletions examples/browser/cookies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { browser } from 'k6/browser';
import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';

export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
thresholds: {
checks: ["rate==1.0"]
}
};

export default async function () {
const page = await browser.newPage();
const context = page.context();

try {
// get cookies from the browser context
await check(await context.cookies(), {
'initial number of cookies should be zero': c => c.length === 0,
});

// add some cookies to the browser context
const unixTimeSinceEpoch = Math.round(new Date() / 1000);
const day = 60*60*24;
const dayAfter = unixTimeSinceEpoch+day;
const dayBefore = unixTimeSinceEpoch-day;
await context.addCookies([
// this cookie expires at the end of the session
{
name: 'testcookie',
value: '1',
sameSite: 'Strict',
domain: '127.0.0.1',
path: '/',
httpOnly: true,
secure: true,
},
// this cookie expires in a day
{
name: 'testcookie2',
value: '2',
sameSite: 'Lax',
domain: '127.0.0.1',
path: '/',
expires: dayAfter,
},
// this cookie expires in the past, so it will be removed.
{
name: 'testcookie3',
value: '3',
sameSite: 'Lax',
domain: '127.0.0.1',
path: '/',
expires: dayBefore
}
]);
let cookies = await context.cookies();
await check(cookies.length, {
'number of cookies should be 2': n => n === 2,
});
await check(cookies[0], {
'cookie 1 name should be testcookie': c => c.name === 'testcookie',
'cookie 1 value should be 1': c => c.value === '1',
'cookie 1 should be session cookie': c => c.expires === -1,
'cookie 1 should have domain': c => c.domain === '127.0.0.1',
'cookie 1 should have path': c => c.path === '/',
'cookie 1 should have sameSite': c => c.sameSite == 'Strict',
'cookie 1 should be httpOnly': c => c.httpOnly === true,
'cookie 1 should be secure': c => c.secure === true,
});
await check(cookies[1], {
'cookie 2 name should be testcookie2': c => c.name === 'testcookie2',
'cookie 2 value should be 2': c => c.value === '2',
});

// let's add more cookies to filter by urls.
await context.addCookies([
{
name: "foo",
value: "42",
sameSite: "Strict",
url: "http://foo.com",
},
{
name: "bar",
value: "43",
sameSite: "Lax",
url: "https://bar.com",
},
{
name: "baz",
value: "44",
sameSite: "Lax",
url: "https://baz.com",
},
]);
cookies = await context.cookies("http://foo.com", "https://baz.com");
await check(cookies.length, {
'number of filtered cookies should be 2': n => n === 2,
});
await check(cookies[0], {
'the first filtered cookie name should be foo': c => c.name === 'foo',
'the first filtered cookie value should be 42': c => c.value === '42',
});
await check(cookies[1], {
'the second filtered cookie name should be baz': c => c.name === 'baz',
'the second filtered cookie value should be 44': c => c.value === '44',
});

// clear cookies
await context.clearCookies();
await check(await context.cookies(), {
'number of cookies should be zero': c => c.length === 0,
});
} finally {
await page.close();
}
}
51 changes: 51 additions & 0 deletions examples/browser/device_emulation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { browser, devices } from 'k6/browser';
import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';

export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
thresholds: {
checks: ["rate==1.0"]
}
}

export default async function() {
const device = devices['iPhone X'];
// The spread operator is currently unsupported by k6's Babel, so use
// Object.assign instead to merge browser context and device options.
// See https://github.com/grafana/k6/issues/2296
const options = Object.assign({ locale: 'es-ES' }, device);
const context = await browser.newContext(options);
const page = await context.newPage();

try {
await page.goto('https://test.k6.io/', { waitUntil: 'networkidle' });
const dimensions = await page.evaluate(() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio
};
});

await check(dimensions, {
'width': d => d.width === device.viewport.width,
'height': d => d.height === device.viewport.height,
'scale': d => d.deviceScaleFactor === device.deviceScaleFactor,
});

if (!__ENV.K6_BROWSER_HEADLESS) {
await page.waitForTimeout(10000);
}
} finally {
await page.close();
}
}
39 changes: 39 additions & 0 deletions examples/browser/dispatch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { browser } from 'k6/browser';
import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';

export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
thresholds: {
checks: ["rate==1.0"]
}
}

export default async function() {
const context = await browser.newContext();
const page = await context.newPage();

try {
await page.goto('https://test.k6.io/', { waitUntil: 'networkidle' });

const contacts = page.locator('a[href="/contacts.php"]');
await contacts.dispatchEvent("click");

await check(page.locator('h3'), {
'header': async lo => {
const text = await lo.textContent();
return text == 'Contact us';
}
});
} finally {
await page.close();
}
}
Loading

0 comments on commit 745f0d4

Please sign in to comment.