mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-09 06:55:03 +00:00
Refactor tests
This commit is contained in:
32
tests/collection/create/create-collection.spec.ts
Normal file
32
tests/collection/create/create-collection.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
|
||||
test('Create collection and add a simple HTTP request', async ({ page, createTmpDir }) => {
|
||||
// Create a new collection
|
||||
await page.getByLabel('Create Collection').click();
|
||||
await page.getByLabel('Name').click();
|
||||
await page.getByLabel('Name').fill('test-collection');
|
||||
await page.getByLabel('Name').press('Tab');
|
||||
await page.getByLabel('Location').fill(await createTmpDir('test-collection'));
|
||||
await page.getByRole('button', { name: 'Create', exact: true }).click();
|
||||
await page.getByText('test-collection').click();
|
||||
|
||||
// Select safe mode
|
||||
await page.getByLabel('Safe Mode').check();
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
|
||||
// Create a new request
|
||||
await page.locator('#create-new-tab').getByRole('img').click();
|
||||
await page.getByPlaceholder('Request Name').fill('r1');
|
||||
await page.locator('#new-request-url .CodeMirror').click();
|
||||
await page.locator('textarea').fill('http://localhost:8081');
|
||||
await page.getByRole('button', { name: 'Create' }).click();
|
||||
|
||||
// Send a request
|
||||
await page.locator('#request-url .CodeMirror').click();
|
||||
await page.locator('textarea').fill('/ping');
|
||||
await page.locator('#send-request').getByTitle('Save Request').click();
|
||||
await page.locator('#send-request').getByRole('img').nth(2).click();
|
||||
|
||||
// Verify the response
|
||||
await expect(page.getByRole('main')).toContainText('200 OK');
|
||||
});
|
||||
43
tests/cookies/cookie-persistence.spec.ts
Normal file
43
tests/cookies/cookie-persistence.spec.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
|
||||
test('should persist cookies across app restarts', async ({ createTmpDir, launchElectronApp }) => {
|
||||
// Create a temporary user-data directory so we control where the cookies store file is written.
|
||||
const userDataPath = await createTmpDir('cookie-persistence');
|
||||
|
||||
const app1 = await launchElectronApp({ userDataPath });
|
||||
const page1 = await app1.firstWindow();
|
||||
await page1.waitForSelector('[data-trigger="cookies"]');
|
||||
|
||||
// Open Cookies modal via the status-bar button.
|
||||
await page1.click('[data-trigger="cookies"]');
|
||||
|
||||
// When no cookies are present the modal shows a centred "Add Cookie" button.
|
||||
await page1.getByRole('button', { name: /Add Cookie/i }).click();
|
||||
|
||||
// Fill out the form.
|
||||
await page1.fill('input[name="domain"]', 'example.com');
|
||||
await page1.fill('input[name="path"]', '/');
|
||||
await page1.fill('input[name="key"]', 'session');
|
||||
await page1.fill('input[name="value"]', 'abc123');
|
||||
await page1.check('input[name="secure"]');
|
||||
await page1.check('input[name="httpOnly"]');
|
||||
|
||||
await page1.getByRole('button', { name: 'Save' }).click();
|
||||
|
||||
await expect(page1.getByText('example.com')).toBeVisible();
|
||||
|
||||
await app1.close();
|
||||
|
||||
// Second launch – verify the cookie was persisted and re-loaded
|
||||
const app2 = await launchElectronApp({ userDataPath });
|
||||
const page2 = await app2.firstWindow();
|
||||
|
||||
// Open the Cookies modal again.
|
||||
await page2.waitForSelector('[data-trigger="cookies"]');
|
||||
await page2.click('[data-trigger="cookies"]');
|
||||
|
||||
// The domain we added earlier should still be present.
|
||||
await expect(page2.getByText('example.com')).toBeVisible();
|
||||
|
||||
await app2.close();
|
||||
});
|
||||
47
tests/cookies/corrupted-passkey.spec.ts
Normal file
47
tests/cookies/corrupted-passkey.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs/promises';
|
||||
|
||||
test('should handle corrupted passkey and still display saved cookie list', async ({ createTmpDir, launchElectronApp }) => {
|
||||
const userDataPath = await createTmpDir('corrupted-passkey');
|
||||
|
||||
const app1 = await launchElectronApp({ userDataPath });
|
||||
// 1. First run – add a cookie via the UI so `cookies.json` is created.
|
||||
const page1 = await app1.firstWindow();
|
||||
|
||||
await page1.waitForSelector('[data-trigger="cookies"]');
|
||||
await page1.click('[data-trigger="cookies"]');
|
||||
await page1.getByRole('button', { name: /Add Cookie/i }).click();
|
||||
|
||||
await page1.fill('input[name="domain"]', 'example.com');
|
||||
await page1.fill('input[name="path"]', '/');
|
||||
await page1.fill('input[name="key"]', 'session');
|
||||
await page1.fill('input[name="value"]', 'abc123');
|
||||
await page1.check('input[name="secure"]');
|
||||
await page1.check('input[name="httpOnly"]');
|
||||
|
||||
await page1.getByRole('button', { name: 'Save' }).click();
|
||||
|
||||
await expect(page1.getByText('example.com')).toBeVisible();
|
||||
|
||||
await app1.close();
|
||||
|
||||
// 2. Corrupt the encryptedPasskey in cookies.json
|
||||
const cookiesFilePath = path.join(userDataPath, 'cookies.json');
|
||||
const raw = await fs.readFile(cookiesFilePath, 'utf-8');
|
||||
const cookiesJson = JSON.parse(raw);
|
||||
cookiesJson.encryptedPasskey = 'deadbeef'; // clearly invalid value
|
||||
await fs.writeFile(cookiesFilePath, JSON.stringify(cookiesJson, null, 2));
|
||||
|
||||
// 3. Second run – Bruno should recover and still list the cookie domain
|
||||
const app2 = await launchElectronApp({ userDataPath });
|
||||
const page2 = await app2.firstWindow();
|
||||
|
||||
await page2.waitForSelector('[data-trigger="cookies"]');
|
||||
await page2.click('[data-trigger="cookies"]');
|
||||
|
||||
// The domain row should still be visible (even if cookie values are blank).
|
||||
await expect(page2.getByText('example.com')).toBeVisible();
|
||||
|
||||
await app2.close();
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
test.describe.serial('bru.setEnvVar(name, value, { persist: true })', () => {
|
||||
test.setTimeout(2 * 10 * 1000);
|
||||
|
||||
test('set env var with persist using script', async ({ pageWithUserData: page, restartApp }) => {
|
||||
// Keep a copy of the original Stage.bru file
|
||||
const originalStageBruPath = path.join(__dirname, 'collection/environments/Stage.bru');
|
||||
const originalStageBruContent = fs.readFileSync(originalStageBruPath, 'utf8');
|
||||
|
||||
// Select the collection and request
|
||||
await page.locator('#sidebar-collection-name').click();
|
||||
await page.getByText('api-setEnvVar-with-persist', { exact: true }).click();
|
||||
|
||||
// open environment dropdown
|
||||
await page.locator('div.current-environment.collection-environment').click();
|
||||
|
||||
// select stage environment
|
||||
await expect(page.locator('.dropdown-item').filter({ hasText: 'Stage' })).toBeVisible();
|
||||
await page.locator('.dropdown-item').filter({ hasText: 'Stage' }).click();
|
||||
await expect(page.locator('.current-environment').filter({ hasText: /Stage/ })).toBeVisible();
|
||||
|
||||
// Send the request
|
||||
await page.locator('#send-request').getByRole('img').nth(2).click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// confirm that the environment variable is set
|
||||
await page.getByTitle('Stage', { exact: true }).click();
|
||||
await page.getByText('Configure', { exact: true }).click();
|
||||
await expect(page.getByRole('row', { name: 'token' }).getByRole('cell').nth(1)).toBeVisible();
|
||||
await expect(page.getByRole('row', { name: 'secret' }).getByRole('cell').nth(2)).toBeVisible();
|
||||
await page.getByText('×').click();
|
||||
|
||||
// we restart the app to confirm that the environment variable is persisted
|
||||
const newApp = await restartApp();
|
||||
const newPage = await newApp.firstWindow();
|
||||
|
||||
// select the collection and request
|
||||
await newPage.locator('#sidebar-collection-name').click();
|
||||
await newPage.getByText('api-setEnvVar-with-persist', { exact: true }).click();
|
||||
|
||||
// open environment dropdown
|
||||
await newPage.locator('div.current-environment.collection-environment').click();
|
||||
await newPage.getByText('Configure', { exact: true }).click();
|
||||
await expect(newPage.getByRole('row', { name: 'token' }).getByRole('cell').nth(1)).toBeVisible();
|
||||
await expect(newPage.getByRole('row', { name: 'secret' }).getByRole('cell').nth(2)).toBeVisible();
|
||||
|
||||
// close the environment modal
|
||||
await newPage.getByText('×').click();
|
||||
|
||||
// Restore the original Stage.bru file
|
||||
fs.writeFileSync(originalStageBruPath, originalStageBruContent);
|
||||
await newPage.close();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
|
||||
test.describe.serial('bru.setEnvVar(name, value)', () => {
|
||||
test.setTimeout(2 * 10 * 1000);
|
||||
|
||||
test('set env var using script', async ({ pageWithUserData: page, restartApp }) => {
|
||||
// Select the collection and request
|
||||
await page.locator('#sidebar-collection-name').click();
|
||||
await page.getByText('api-setEnvVar-without-persist', { exact: true }).click();
|
||||
|
||||
// open environment dropdown
|
||||
await page.locator('div.current-environment.collection-environment').click();
|
||||
|
||||
// select stage environment
|
||||
await expect(page.locator('.dropdown-item').filter({ hasText: 'Stage' })).toBeVisible();
|
||||
await page.locator('.dropdown-item').filter({ hasText: 'Stage' }).click();
|
||||
await expect(page.locator('.current-environment').filter({ hasText: /Stage/ })).toBeVisible();
|
||||
|
||||
// Send the request
|
||||
await page.locator('#send-request').getByRole('img').nth(2).click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// confirm that the environment variable is set
|
||||
await page.getByTitle('Stage', { exact: true }).click();
|
||||
await page.getByText('Configure', { exact: true }).click();
|
||||
await expect(page.getByRole('row', { name: 'token' }).getByRole('cell').nth(1)).toBeVisible();
|
||||
await expect(page.getByRole('row', { name: 'secret' }).getByRole('cell').nth(2)).toBeVisible();
|
||||
await page.getByText('×').click();
|
||||
|
||||
// we restart the app to confirm that the environment variable is not persisted
|
||||
const newApp = await restartApp();
|
||||
const newPage = await newApp.firstWindow();
|
||||
|
||||
// select the collection and request
|
||||
await newPage.locator('#sidebar-collection-name').click();
|
||||
await newPage.getByText('api-setEnvVar-without-persist', { exact: true }).click();
|
||||
|
||||
// open environment dropdown
|
||||
await newPage.locator('div.current-environment.collection-environment').click();
|
||||
await newPage.getByText('Configure', { exact: true }).click();
|
||||
|
||||
// ensure that the environment variable is not persisted
|
||||
await expect(newPage.locator('table.environment-variables tbody')).not.toContainText('token');
|
||||
|
||||
// close the environment variable modal
|
||||
await newPage.getByText('×').click();
|
||||
await newPage.close();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
meta {
|
||||
name: api-setEnvVar-with-persist
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
bru.setEnvVar("token", "secret", { persist: true });
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
meta {
|
||||
name: api-setEnvVar-without-persist
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
bru.setEnvVar("token", "secret");
|
||||
}
|
||||
5
tests/environments/api-setEnvVar/collection/bruno.json
Normal file
5
tests/environments/api-setEnvVar/collection/bruno.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": "1",
|
||||
"name": "collection",
|
||||
"type": "collection"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
vars {
|
||||
host: https://testbench-sanity.usebruno.com
|
||||
token: secret
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"collections": [
|
||||
{
|
||||
"path": "{{projectRoot}}/tests/environments/api-setEnvVar/collection",
|
||||
"securityConfig": {
|
||||
"jsSandboxMode": "safe"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"maximized": true,
|
||||
"lastOpenedCollections": [
|
||||
"{{projectRoot}}/tests/environments/api-setEnvVar/collection"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": "1",
|
||||
"name": "multiline-variables",
|
||||
"type": "collection"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
meta {
|
||||
name: multiline-variables
|
||||
type: collection
|
||||
version: 1.0.0
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
vars {
|
||||
host: https://www.httpfaker.org
|
||||
multiline_data: '''
|
||||
line1
|
||||
line2
|
||||
line3
|
||||
'''
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
meta {
|
||||
name: multiline-test
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
post {
|
||||
url: {{host}}/api/echo
|
||||
body: json
|
||||
auth: none
|
||||
}
|
||||
|
||||
body:json {
|
||||
{{multiline_data_json}}
|
||||
}
|
||||
|
||||
tests {
|
||||
test("should post multiline data successfully", function() {
|
||||
expect(res.getStatus()).to.equal(200);
|
||||
});
|
||||
|
||||
test("should resolve multiline_data_json variable correctly", function() {
|
||||
const body = res.getBody();
|
||||
// HTTP Faker echo endpoint returns the request body in body.body
|
||||
// Verify the multiline JSON variable was resolved and parsed correctly
|
||||
expect(body.body.user.name).to.equal("John Doe");
|
||||
expect(body.body.user.email).to.equal("john@example.com");
|
||||
expect(body.body.user.preferences.theme).to.equal("dark");
|
||||
expect(body.body.user.preferences.notifications).to.equal(true);
|
||||
});
|
||||
|
||||
test("should preserve JSON structure from multiline variable", function() {
|
||||
const body = res.getBody();
|
||||
// Verify the complete JSON structure was preserved
|
||||
expect(body.body.metadata.created).to.equal("2025-09-03");
|
||||
expect(body.body.metadata.version).to.equal("1.0");
|
||||
});
|
||||
|
||||
test("should resolve host variable in URL", function() {
|
||||
const body = res.getBody();
|
||||
// Verify the host variable was resolved in the request URL
|
||||
expect(body.url).to.equal("https://www.httpfaker.org/api/echo");
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
meta {
|
||||
name: request
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
post {
|
||||
url: {{host}}/api/echo
|
||||
body: text
|
||||
auth: none
|
||||
}
|
||||
|
||||
body:json {
|
||||
Ping Test Request
|
||||
Host: {{host}}
|
||||
|
||||
Multiline Data:
|
||||
{{multiline_data}}
|
||||
|
||||
End of multiline content.
|
||||
}
|
||||
|
||||
body:text {
|
||||
{{host}}
|
||||
{{multiline_data}}
|
||||
}
|
||||
|
||||
tests {
|
||||
test("should get 200 response", function() {
|
||||
expect(res.getStatus()).to.equal(200);
|
||||
});
|
||||
|
||||
test("should resolve multiline_data variable correctly", function() {
|
||||
const body = res.getBody();
|
||||
// Verify the multiline variable was resolved and contains all three lines
|
||||
expect(body.body).to.equal("https://www.httpfaker.org\nline1\nline2\nline3");
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"collections": [
|
||||
{
|
||||
"path": "{{projectRoot}}/tests/environments/multiline-variables/collection",
|
||||
"securityConfig": {
|
||||
"jsSandboxMode": "developer"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"maximized": true,
|
||||
"lastOpenedCollections": [
|
||||
"{{projectRoot}}/tests/environments/multiline-variables/collection"
|
||||
],
|
||||
"request": {
|
||||
"sslVerification": false,
|
||||
"customCaCertificate": {
|
||||
"enabled": false,
|
||||
"filePath": null
|
||||
}
|
||||
},
|
||||
"font": {
|
||||
"codeFont": "default"
|
||||
},
|
||||
"proxy": {
|
||||
"enabled": false,
|
||||
"protocol": "http",
|
||||
"hostname": "",
|
||||
"port": "",
|
||||
"auth": {
|
||||
"enabled": false,
|
||||
"username": "",
|
||||
"password": ""
|
||||
},
|
||||
"bypassProxy": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
|
||||
test.describe('Multiline Variables - Read Environment Test', () => {
|
||||
test('should read existing multiline environment variables', async ({ pageWithUserData: page }) => {
|
||||
test.setTimeout(30 * 1000);
|
||||
|
||||
// open the collection
|
||||
await expect(page.getByTitle('multiline-variables')).toBeVisible();
|
||||
await page.getByTitle('multiline-variables').click();
|
||||
|
||||
// open request
|
||||
await expect(page.getByTitle('request', { exact: true })).toBeVisible();
|
||||
await page.getByTitle('request', { exact: true }).click();
|
||||
|
||||
// open environment dropdown
|
||||
await page.locator('div.current-environment.collection-environment').click();
|
||||
|
||||
// select test environment
|
||||
await expect(page.locator('.dropdown-item').filter({ hasText: 'Test' })).toBeVisible();
|
||||
await page.locator('.dropdown-item').filter({ hasText: 'Test' }).click();
|
||||
await expect(page.locator('.current-environment').filter({ hasText: /Test/ })).toBeVisible();
|
||||
|
||||
// send request
|
||||
const sendButton = page.locator('#send-request').getByRole('img').nth(2);
|
||||
await expect(sendButton).toBeVisible();
|
||||
await sendButton.click();
|
||||
await expect(page.locator('.response-status-code.text-ok')).toBeVisible();
|
||||
await expect(page.locator('.response-status-code')).toContainText('200');
|
||||
|
||||
// response pane should contain the expected multiline text in JSON body
|
||||
const responsePane = page.locator('.response-pane');
|
||||
await expect(responsePane).toContainText('"body": "https://www.httpfaker.org\\nline1\\nline2\\nline3"');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
|
||||
test.describe('Multiline Variables - Write Test', () => {
|
||||
test('should create and use multiline environment variable dynamically', async ({ pageWithUserData: page }) => {
|
||||
test.setTimeout(60 * 1000);
|
||||
|
||||
// open the collection
|
||||
await expect(page.getByTitle('multiline-variables')).toBeVisible();
|
||||
await page.getByTitle('multiline-variables').click();
|
||||
|
||||
// open request
|
||||
await expect(page.getByTitle('multiline-test', { exact: true })).toBeVisible();
|
||||
await page.getByTitle('multiline-test', { exact: true }).click();
|
||||
|
||||
// open environment dropdown
|
||||
await page.locator('div.current-environment.collection-environment').click();
|
||||
|
||||
// select test environment
|
||||
await expect(page.locator('.dropdown-item').filter({ hasText: 'Test' })).toBeVisible();
|
||||
await page.locator('.dropdown-item').filter({ hasText: 'Test' }).click();
|
||||
await expect(page.locator('.current-environment').filter({ hasText: /Test/ })).toBeVisible();
|
||||
|
||||
// select configure button from environment dropdown
|
||||
await expect(page.getByTitle('Test', { exact: true })).toBeVisible();
|
||||
await page.getByTitle('Test', { exact: true }).click();
|
||||
|
||||
// open environment configuration
|
||||
await expect(page.locator('#Configure')).toBeVisible();
|
||||
await page.locator('#Configure').click();
|
||||
|
||||
// add variable
|
||||
await page.getByRole('button', { name: /Add.*Variable/i }).click();
|
||||
const valueTextarea = page.locator('.bruno-modal-card textarea').last();
|
||||
await expect(valueTextarea).toBeVisible();
|
||||
|
||||
const jsonValue = `{
|
||||
"user": {
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"preferences": {
|
||||
"theme": "dark",
|
||||
"notifications": true
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"created": "2025-09-03",
|
||||
"version": "1.0"
|
||||
}
|
||||
}`;
|
||||
|
||||
// fill variable value
|
||||
await valueTextarea.fill(jsonValue);
|
||||
await page.keyboard.press('Shift+Tab');
|
||||
await page.keyboard.type('multiline_data_json');
|
||||
|
||||
// save variable and close config
|
||||
const saveVarButton = page.getByRole('button', { name: /Save/i });
|
||||
await expect(saveVarButton).toBeVisible();
|
||||
await saveVarButton.click();
|
||||
|
||||
await expect(page.locator('.close.cursor-pointer')).toBeVisible();
|
||||
await page.locator('.close.cursor-pointer').click();
|
||||
|
||||
// send request
|
||||
const sendButton = page.locator('#send-request').getByRole('img').nth(2);
|
||||
await expect(sendButton).toBeVisible();
|
||||
await sendButton.click();
|
||||
|
||||
// wait for response status
|
||||
await expect(page.locator('.response-status-code.text-ok')).toBeVisible();
|
||||
await expect(page.locator('.response-status-code')).toContainText('200');
|
||||
|
||||
// verify multiline JSON variable resolution in response
|
||||
const expectedBody =
|
||||
'{\n "user": {\n "name": "John Doe",\n "email": "john@example.com",\n "preferences": {\n "theme": "dark",\n "notifications": true\n }\n },\n "metadata": {\n "created": "2025-09-03",\n "version": "1.0"\n }\n}';
|
||||
await expect(page.locator('.response-pane')).toContainText(`"body": ${JSON.stringify(expectedBody)}`);
|
||||
});
|
||||
|
||||
// clean up created variable after test
|
||||
test.afterEach(async () => {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const testBruPath = path.join(__dirname, 'collection/environments/Test.bru');
|
||||
let content = fs.readFileSync(testBruPath, 'utf8');
|
||||
|
||||
// remove the multiline_data_json variable and its content
|
||||
content = content.replace(/\s*multiline_data_json:\s*'''\s*[\s\S]*?\s*'''/g, '');
|
||||
|
||||
fs.writeFileSync(testBruPath, content);
|
||||
});
|
||||
});
|
||||
25
tests/footer/notifications/notifications.spec.js
Normal file
25
tests/footer/notifications/notifications.spec.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
|
||||
test.describe('Notifications Modal', () => {
|
||||
test('should open notifications modal when clicking bell icon and close with close button', async ({ page }) => {
|
||||
// Get the notification bell icon in the status bar
|
||||
const notificationBell = page.getByLabel('Check all Notifications');
|
||||
|
||||
// Click on the bell icon to open notifications
|
||||
await notificationBell.click();
|
||||
|
||||
// Get modal elements
|
||||
const notificationsModal = page.locator('.bruno-modal');
|
||||
const modalCloseButton = notificationsModal.locator('div.bruno-modal-header div.close');
|
||||
|
||||
// Verify modal is visible and has the correct title
|
||||
await expect(notificationsModal).toBeVisible();
|
||||
await expect(notificationsModal.locator('.bruno-modal-header-title')).toContainText('NOTIFICATIONS');
|
||||
|
||||
// Click the close button
|
||||
await modalCloseButton.click();
|
||||
|
||||
// Verify modal is closed
|
||||
await expect(notificationsModal).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
36
tests/footer/sidebar-toggle/sidebar-toggle.spec.js
Normal file
36
tests/footer/sidebar-toggle/sidebar-toggle.spec.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
|
||||
test.describe('Sidebar Toggle', () => {
|
||||
test('should toggle sidebar visibility when clicking the toggle button', async ({ page }) => {
|
||||
// Get the sidebar and toggle button elements
|
||||
const sidebar = page.locator('aside.sidebar');
|
||||
const toggleButton = page.getByLabel('Toggle Sidebar');
|
||||
const dragHandle = page.locator('.sidebar-drag-handle');
|
||||
|
||||
// Initial state - sidebar and drag handle should be visible
|
||||
await expect(sidebar).toBeVisible();
|
||||
await expect(dragHandle).toBeVisible();
|
||||
|
||||
// Click toggle to hide sidebar
|
||||
await toggleButton.click();
|
||||
|
||||
// Wait for transition to complete and verify sidebar and drag handle are hidden
|
||||
await expect(sidebar).not.toBeVisible();
|
||||
await expect(dragHandle).not.toBeVisible();
|
||||
|
||||
// Verify the sidebar has collapsed width
|
||||
const sidebarBox = await sidebar.boundingBox();
|
||||
expect(sidebarBox?.width).toBe(0);
|
||||
|
||||
// Click toggle again to show sidebar
|
||||
await toggleButton.click();
|
||||
|
||||
// Wait for transition and verify sidebar and drag handle are visible again
|
||||
await expect(sidebar).toBeVisible();
|
||||
await expect(dragHandle).toBeVisible();
|
||||
|
||||
// Verify the sidebar has expanded width
|
||||
const expandedSidebarBox = await sidebar.boundingBox();
|
||||
expect(expandedSidebarBox?.width).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
38
tests/import/bruno/001-import-bruno-testbench.spec.ts
Normal file
38
tests/import/bruno/001-import-bruno-testbench.spec.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
|
||||
test.describe('Import Bruno Testbench Collection', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test.beforeAll(async ({ page }) => {
|
||||
// Navigate back to homescreen after all tests
|
||||
await page.locator('.bruno-logo').click();
|
||||
});
|
||||
|
||||
test('Import Bruno Testbench collection successfully', async ({ page }) => {
|
||||
const brunoFile = path.join(testDataDir, 'bruno-testbench.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', brunoFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Verify that the Import Collection modal is displayed (for location selection)
|
||||
const locationModal = page.getByRole('dialog');
|
||||
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
// Wait for collection to appear in the location modal
|
||||
await expect(locationModal.getByText('bruno-testbench')).toBeVisible();
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
31
tests/import/bruno/002-import-bruno-corrupted-fails.spec.ts
Normal file
31
tests/import/bruno/002-import-bruno-corrupted-fails.spec.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Import Corrupted Bruno Collection - Should Fail', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Import Bruno collection with invalid JSON structure should fail', async ({ page }) => {
|
||||
const brunoFile = path.join(testDataDir, 'bruno-malformed.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', brunoFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Check for JSON parsing error
|
||||
const hasImportError = await page.getByText('Failed to parse the file – ensure it is valid JSON or YAML').first().isVisible();
|
||||
|
||||
// Either parsing error or import error should be shown
|
||||
expect(hasImportError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Import Bruno Collection - Missing Required Schema Fields', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Import Bruno collection missing required version field should fail', async ({ page }) => {
|
||||
const brunoFile = path.join(testDataDir, 'bruno-missing-required-fields.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', brunoFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Check for schema validation error messages
|
||||
const hasImportError = await page.getByText('Import collection failed').first().isVisible();
|
||||
|
||||
expect(hasImportError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
20
tests/import/file-types/001-file-input-acceptance.spec.ts
Normal file
20
tests/import/file-types/001-file-input-acceptance.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
|
||||
test.describe('File Input Acceptance', () => {
|
||||
test('File input accepts expected file types', async ({ page }) => {
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Check that file input exists (even if hidden)
|
||||
const fileInput = page.locator('input[type="file"]');
|
||||
await expect(fileInput).toBeAttached();
|
||||
|
||||
// Verify it accepts the expected file types
|
||||
const acceptValue = await fileInput.getAttribute('accept');
|
||||
expect(acceptValue).toContain('.json');
|
||||
expect(acceptValue).toContain('.yaml');
|
||||
expect(acceptValue).toContain('.yml');
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
28
tests/import/file-types/002-invalid-file-handling.spec.ts
Normal file
28
tests/import/file-types/002-invalid-file-handling.spec.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Invalid File Handling', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Handle invalid file without crashing', async ({ page }) => {
|
||||
const invalidFile = path.join(testDataDir, 'invalid.txt');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', invalidFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
const hasError = await page.getByText("Failed to parse the file – ensure it is valid JSON or YAML").isVisible();
|
||||
expect(hasError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
32
tests/import/insomnia/001-import-insomnia-v4.spec.ts
Normal file
32
tests/import/insomnia/001-import-insomnia-v4.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Import Insomnia Collection v4', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Import Insomnia Collection v4 successfully', async ({ page }) => {
|
||||
const insomniaFile = path.join(testDataDir, 'insomnia-v4.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', insomniaFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Verify that the Import Collection modal is displayed (for location selection)
|
||||
const locationModal = page.getByRole('dialog');
|
||||
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
// Wait for collection to appear in the location modal
|
||||
await expect(locationModal.getByText('Test API Collection v4')).toBeVisible();
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
32
tests/import/insomnia/002-import-insomnia-v5.spec.ts
Normal file
32
tests/import/insomnia/002-import-insomnia-v5.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Import Insomnia Collection v5', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Import Insomnia Collection v5 successfully', async ({ page }) => {
|
||||
const insomniaFile = path.join(testDataDir, 'insomnia-v5.yaml');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', insomniaFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Verify that the Import Collection modal is displayed (for location selection)
|
||||
const locationModal = page.getByRole('dialog');
|
||||
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
// Wait for collection to appear in the location modal
|
||||
await expect(locationModal.getByText('Test API Collection v5')).toBeVisible();
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
29
tests/import/insomnia/003-invalid-missing-collection.spec.ts
Normal file
29
tests/import/insomnia/003-invalid-missing-collection.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Invalid Insomnia Collection - Missing Collection Array', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Handle Insomnia v5 collection missing collection array', async ({ page }) => {
|
||||
const insomniaFile = path.join(testDataDir, 'insomnia-v5-invalid-missing-collection.yaml');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', insomniaFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Check for error message
|
||||
const hasError = await page.getByText('Import collection failed').first().isVisible();
|
||||
expect(hasError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
29
tests/import/insomnia/004-malformed-structure.spec.ts
Normal file
29
tests/import/insomnia/004-malformed-structure.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Invalid Insomnia Collection - Malformed Structure', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Handle malformed Insomnia collection structure', async ({ page }) => {
|
||||
const insomniaFile = path.join(testDataDir, 'insomnia-malformed.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', insomniaFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Check for error message - this should fail during JSON parsing
|
||||
const hasError = await page.getByText('Failed to parse the file').isVisible();
|
||||
expect(hasError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
32
tests/import/openapi/001-import-openapi-yaml.spec.ts
Normal file
32
tests/import/openapi/001-import-openapi-yaml.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Import OpenAPI v3 YAML Collection', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Import comprehensive OpenAPI v3 YAML successfully', async ({ page }) => {
|
||||
const openApiFile = path.join(testDataDir, 'openapi-comprehensive.yaml');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', openApiFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Verify that the Import Collection modal is displayed (for location selection)
|
||||
const locationModal = page.getByRole('dialog');
|
||||
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
// Wait for collection to appear in the location modal
|
||||
await expect(locationModal.getByText('Comprehensive API Test Collection')).toBeVisible();
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
32
tests/import/openapi/002-import-openapi-json.spec.ts
Normal file
32
tests/import/openapi/002-import-openapi-json.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Import OpenAPI v3 JSON Collection', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Import simple OpenAPI v3 JSON successfully', async ({ page }) => {
|
||||
const openApiFile = path.join(testDataDir, 'openapi-simple.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', openApiFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Verify that the Import Collection modal is displayed (for location selection)
|
||||
const locationModal = page.getByRole('dialog');
|
||||
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
// Wait for collection to appear in the location modal
|
||||
await expect(locationModal.getByText('Simple Test API')).toBeVisible();
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
31
tests/import/openapi/003-missing-info.spec.ts
Normal file
31
tests/import/openapi/003-missing-info.spec.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Invalid OpenAPI - Missing Info Section', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Handle OpenAPI specification missing required info section', async ({ page }) => {
|
||||
const openApiFile = path.join(testDataDir, 'openapi-missing-info.yaml');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', openApiFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// The OpenAPI parser might handle missing info gracefully with defaults
|
||||
const hasError = await page.getByText('Import collection failed').first().isVisible();
|
||||
|
||||
// Either should show an error or create an "Untitled Collection"
|
||||
expect(hasError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
32
tests/import/openapi/004-malformed-yaml.spec.ts
Normal file
32
tests/import/openapi/004-malformed-yaml.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Invalid OpenAPI - Malformed YAML', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Handle malformed OpenAPI YAML structure', async ({ page }) => {
|
||||
const openApiFile = path.join(testDataDir, 'openapi-malformed.yaml');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', openApiFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Check for error message - this should fail during YAML parsing
|
||||
const hasParseError = await page.getByText('Failed to parse the file').isVisible();
|
||||
const hasImportError = await page.getByText('Import collection failed').isVisible();
|
||||
|
||||
// Either parsing error or import error should be shown
|
||||
expect(hasParseError || hasImportError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
32
tests/import/postman/001-import-postman-v21.spec.ts
Normal file
32
tests/import/postman/001-import-postman-v21.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Import Postman Collection v2.1', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Import Postman Collection v2.1 successfully', async ({ page }) => {
|
||||
const postmanFile = path.join(testDataDir, 'postman-v21.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', postmanFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Verify that the Import Collection modal is displayed (for location selection)
|
||||
const locationModal = page.getByRole('dialog');
|
||||
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
// Wait for collection to appear in the location modal
|
||||
await expect(locationModal.getByText('Postman v2.1 Collection')).toBeVisible();
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
32
tests/import/postman/002-import-postman-v20.spec.ts
Normal file
32
tests/import/postman/002-import-postman-v20.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Import Postman Collection v2.0', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Import Postman Collection v2.0 successfully', async ({ page }) => {
|
||||
const postmanFile = path.join(testDataDir, 'postman-v20.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', postmanFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Verify that the Import Collection modal is displayed (for location selection)
|
||||
const locationModal = page.getByRole('dialog');
|
||||
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
// Wait for collection to appear in the location modal
|
||||
await expect(locationModal.getByText('Postman v2.0 Collection')).toBeVisible();
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
29
tests/import/postman/003-invalid-missing-info.spec.ts
Normal file
29
tests/import/postman/003-invalid-missing-info.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Invalid Postman Collection - Missing Info', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Handle Postman collection missing required info field', async ({ page }) => {
|
||||
const postmanFile = path.join(testDataDir, 'postman-invalid-missing-info.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', postmanFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Check for error message
|
||||
const hasError = await page.getByText('Import collection failed').isVisible();
|
||||
expect(hasError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
29
tests/import/postman/004-invalid-schema.spec.ts
Normal file
29
tests/import/postman/004-invalid-schema.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Invalid Postman Collection - Invalid Schema', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Handle Postman collection with invalid schema version', async ({ page }) => {
|
||||
const postmanFile = path.join(testDataDir, 'postman-invalid-schema.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', postmanFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Check for error message
|
||||
const hasError = await page.getByText('Conversion failed').isVisible();
|
||||
expect(hasError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
29
tests/import/postman/005-malformed-structure.spec.ts
Normal file
29
tests/import/postman/005-malformed-structure.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Invalid Postman Collection - Malformed Structure', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Handle malformed Postman collection structure', async ({ page }) => {
|
||||
const postmanFile = path.join(testDataDir, 'postman-malformed.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', postmanFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Check for error message
|
||||
const hasError = await page.getByText('Import collection failed').first().isVisible();
|
||||
expect(hasError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
29
tests/import/postman/006-invalid-json.spec.ts
Normal file
29
tests/import/postman/006-invalid-json.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import * as path from 'path';
|
||||
|
||||
test.describe('Invalid Postman Collection - Invalid JSON', () => {
|
||||
const testDataDir = path.join(__dirname, '../test-data');
|
||||
|
||||
test('Handle invalid JSON syntax', async ({ page }) => {
|
||||
const postmanFile = path.join(testDataDir, 'postman-invalid-schema.json');
|
||||
|
||||
await page.getByRole('button', { name: 'Import Collection' }).click();
|
||||
|
||||
// Wait for import collection modal to be ready
|
||||
const importModal = page.getByRole('dialog');
|
||||
await importModal.waitFor({ state: 'visible' });
|
||||
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
|
||||
|
||||
await page.setInputFiles('input[type="file"]', postmanFile);
|
||||
|
||||
// Wait for the loader to disappear
|
||||
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
|
||||
|
||||
// Check for error message
|
||||
const hasError = await page.getByText('Conversion failed').first().isVisible();
|
||||
expect(hasError).toBe(true);
|
||||
|
||||
// Cleanup: close any open modals
|
||||
await page.locator('[data-test-id="modal-close-button"]').click();
|
||||
});
|
||||
});
|
||||
66
tests/import/test-data/bruno-invalid-corrupted.json
Normal file
66
tests/import/test-data/bruno-invalid-corrupted.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"version": "1",
|
||||
"uid": "corrupted_bruno_collection",
|
||||
"name": "Corrupted Bruno Collection",
|
||||
"items": [
|
||||
{
|
||||
"uid": "corrupted_request",
|
||||
"type": "invalid-request-type",
|
||||
"name": "Invalid Request Type",
|
||||
"seq": 1,
|
||||
"request": {
|
||||
"url": "https://example.com/api",
|
||||
"method": "INVALID_METHOD",
|
||||
"headers": "this should be an array not a string",
|
||||
"params": null,
|
||||
"body": {
|
||||
"mode": "invalid-mode",
|
||||
"invalidField": "this field doesn't exist in schema"
|
||||
},
|
||||
"auth": {
|
||||
"mode": "unknown-auth-type",
|
||||
"invalidAuth": {
|
||||
"badField": "invalid value"
|
||||
}
|
||||
},
|
||||
"script": "this should be an object not a string",
|
||||
"vars": "this should be an object not a string",
|
||||
"assertions": "this should be an array not a string",
|
||||
"tests": 12345,
|
||||
"docs": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "missing_required_fields",
|
||||
"type": "http-request",
|
||||
"name": "Missing Required Fields",
|
||||
"seq": 2
|
||||
}
|
||||
],
|
||||
"environments": [
|
||||
{
|
||||
"uid": "invalid_env",
|
||||
"name": "Invalid Environment",
|
||||
"variables": "this should be an array not a string"
|
||||
}
|
||||
],
|
||||
"activeEnvironmentUid": "non_existent_environment_id",
|
||||
"root": {
|
||||
"request": {
|
||||
"headers": "invalid headers format",
|
||||
"auth": {
|
||||
"mode": "completely-unknown-auth"
|
||||
},
|
||||
"script": 42,
|
||||
"vars": false,
|
||||
"tests": null
|
||||
}
|
||||
},
|
||||
"invalidTopLevelField": "this field doesn't belong here",
|
||||
"brunoConfig": {
|
||||
"version": "999",
|
||||
"name": "Invalid Config",
|
||||
"type": "invalid-type",
|
||||
"invalidConfigField": true
|
||||
}
|
||||
}
|
||||
43
tests/import/test-data/bruno-malformed.json
Normal file
43
tests/import/test-data/bruno-malformed.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"version": "1",
|
||||
"uid": "malformed_bruno_collection",
|
||||
"name": "Malformed Bruno Collection",
|
||||
"items": [
|
||||
{
|
||||
"uid": "malformed_request",
|
||||
"type": "http-request",
|
||||
"name": "Malformed Request",
|
||||
"seq": 1,
|
||||
"request": {
|
||||
"url": "https://example.com/api",
|
||||
"method": "GET",
|
||||
"headers": [],
|
||||
"params": [],
|
||||
"body": {
|
||||
"mode": "none"
|
||||
},
|
||||
"auth": {
|
||||
"mode": "none"
|
||||
},
|
||||
"script": {},
|
||||
"vars": {},
|
||||
"assertions": [],
|
||||
"tests": "",
|
||||
"docs": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"environments": [],
|
||||
"activeEnvironmentUid": null,
|
||||
"root": {
|
||||
"request": {
|
||||
"headers": [],
|
||||
"auth": {
|
||||
"mode": "none"
|
||||
},
|
||||
"script": {},
|
||||
"vars": {},
|
||||
"tests": ""
|
||||
}
|
||||
}
|
||||
// Missing comma and closing bracket - this makes it malformed JSON
|
||||
2939
tests/import/test-data/bruno-missing-required-fields.json
Normal file
2939
tests/import/test-data/bruno-missing-required-fields.json
Normal file
File diff suppressed because it is too large
Load Diff
2940
tests/import/test-data/bruno-testbench.json
Normal file
2940
tests/import/test-data/bruno-testbench.json
Normal file
File diff suppressed because it is too large
Load Diff
0
tests/import/test-data/empty-file.json
Normal file
0
tests/import/test-data/empty-file.json
Normal file
19
tests/import/test-data/insomnia-malformed.json
Normal file
19
tests/import/test-data/insomnia-malformed.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"_type": "export",
|
||||
"__export_format": 4,
|
||||
"resources": [
|
||||
{
|
||||
"_id": "req_123",
|
||||
"parentId": "wrk_456",
|
||||
"url": "https://api.example.com/users",
|
||||
"name": "Get Users",
|
||||
"method": "GET",
|
||||
"_type": "request"
|
||||
},
|
||||
{
|
||||
"_id": "wrk_456",
|
||||
"name": "Test Collection",
|
||||
"_type": "workspace"
|
||||
// Missing comma and closing bracket - malformed JSON
|
||||
}
|
||||
]
|
||||
113
tests/import/test-data/insomnia-v4.json
Normal file
113
tests/import/test-data/insomnia-v4.json
Normal file
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"_type": "export",
|
||||
"__export_format": 4,
|
||||
"__export_date": "2025-01-01T12:00:00.000Z",
|
||||
"__export_source": "insomnia.desktop.app:v10.3.1",
|
||||
"resources": [
|
||||
{
|
||||
"_id": "req_fdedb34f7d5541d0aa7a917ce37ec067",
|
||||
"parentId": "wrk_398c634c4fbc4774bcff39cbff44b31b",
|
||||
"modified": 1689952276171,
|
||||
"created": 1689951240510,
|
||||
"url": "{{baseUrl}}/api/users",
|
||||
"name": "Get Users",
|
||||
"description": "Fetch all users from the API",
|
||||
"method": "GET",
|
||||
"body": {},
|
||||
"parameters": [],
|
||||
"headers": [
|
||||
{
|
||||
"name": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"authentication": {},
|
||||
"metaSortKey": -1689951414329,
|
||||
"isPrivate": false,
|
||||
"settingStoreCookies": true,
|
||||
"settingSendCookies": true,
|
||||
"settingDisableRenderRequestBody": false,
|
||||
"settingEncodeUrl": true,
|
||||
"settingRebuildPath": true,
|
||||
"settingFollowRedirects": "global",
|
||||
"_type": "request"
|
||||
},
|
||||
{
|
||||
"_id": "req_c920d219404144e8bc6b6bd36f442974",
|
||||
"parentId": "fld_ab2a1533f2be48c194883bf07d693292",
|
||||
"modified": 1689952281595,
|
||||
"created": 1689951281897,
|
||||
"url": "{{baseUrl}}/api/auth/login",
|
||||
"name": "Login User",
|
||||
"description": "User authentication endpoint",
|
||||
"method": "POST",
|
||||
"body": {
|
||||
"mimeType": "application/json",
|
||||
"text": "{\n \"username\": \"admin\",\n \"password\": \"password123\"\n}"
|
||||
},
|
||||
"parameters": [],
|
||||
"headers": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"authentication": {},
|
||||
"metaSortKey": -1689951404530.5625,
|
||||
"isPrivate": false,
|
||||
"settingStoreCookies": true,
|
||||
"settingSendCookies": true,
|
||||
"settingDisableRenderRequestBody": false,
|
||||
"settingEncodeUrl": true,
|
||||
"settingRebuildPath": true,
|
||||
"settingFollowRedirects": "global",
|
||||
"_type": "request"
|
||||
},
|
||||
{
|
||||
"_id": "fld_ab2a1533f2be48c194883bf07d693292",
|
||||
"parentId": "wrk_398c634c4fbc4774bcff39cbff44b31b",
|
||||
"modified": 1743683080329,
|
||||
"created": 1743683080329,
|
||||
"name": "Authentication",
|
||||
"description": "Authentication related endpoints",
|
||||
"environment": {},
|
||||
"environmentPropertyOrder": null,
|
||||
"metaSortKey": -1743683080329,
|
||||
"_type": "request_group"
|
||||
},
|
||||
{
|
||||
"_id": "wrk_398c634c4fbc4774bcff39cbff44b31b",
|
||||
"parentId": null,
|
||||
"modified": 1743678539806,
|
||||
"created": 1743678539806,
|
||||
"name": "Test API Collection v4",
|
||||
"description": "Test collection for Insomnia v4 format",
|
||||
"scope": "collection",
|
||||
"_type": "workspace"
|
||||
},
|
||||
{
|
||||
"_id": "env_93781eb62f074459bb67692112b76da0",
|
||||
"parentId": "wrk_398c634c4fbc4774bcff39cbff44b31b",
|
||||
"modified": 1743681240772,
|
||||
"created": 1689951235312,
|
||||
"name": "Base Environment",
|
||||
"data": {
|
||||
"baseUrl": "https://api.example.com"
|
||||
},
|
||||
"dataPropertyOrder": null,
|
||||
"color": null,
|
||||
"isPrivate": false,
|
||||
"metaSortKey": 1689951235312,
|
||||
"_type": "environment"
|
||||
},
|
||||
{
|
||||
"_id": "jar_09963a0322c24b698ecd2f866ae9a6ab",
|
||||
"parentId": "wrk_398c634c4fbc4774bcff39cbff44b31b",
|
||||
"modified": 1689951235313,
|
||||
"created": 1689951235313,
|
||||
"name": "Default Jar",
|
||||
"cookies": [],
|
||||
"_type": "cookie_jar"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
type: collection.insomnia.rest/5.0
|
||||
name: Invalid v5 Collection
|
||||
meta:
|
||||
id: wrk_7faf891d273e4b7ea82bdbaa641ee17a
|
||||
created: 1743683067888
|
||||
modified: 1743683067888
|
||||
# Missing collection array - this should cause import to fail
|
||||
cookieJar:
|
||||
name: Default Jar
|
||||
meta:
|
||||
id: jar_25f97142fa796ae37f7f4937c0ebf3a07869d0a8
|
||||
created: 1743683067908
|
||||
modified: 1743683833282
|
||||
cookies: []
|
||||
environments:
|
||||
name: Base Environment
|
||||
meta:
|
||||
id: env_25f97142fa796ae37f7f4937c0ebf3a07869d0a8
|
||||
created: 1743683067895
|
||||
modified: 1743683476058
|
||||
isPrivate: false
|
||||
data:
|
||||
base_url: https://api.example.com
|
||||
129
tests/import/test-data/insomnia-v5.yaml
Normal file
129
tests/import/test-data/insomnia-v5.yaml
Normal file
@@ -0,0 +1,129 @@
|
||||
type: collection.insomnia.rest/5.0
|
||||
name: Test API Collection v5
|
||||
meta:
|
||||
id: wrk_7faf891d273e4b7ea82bdbaa641ee17a
|
||||
created: 1743683067888
|
||||
modified: 1743683067888
|
||||
collection:
|
||||
- name: API Tests
|
||||
meta:
|
||||
id: fld_ab2a1533f2be48c194883bf07d693292
|
||||
created: 1743683080329
|
||||
modified: 1743683080329
|
||||
sortKey: -1743683080329
|
||||
children:
|
||||
- name: Authentication
|
||||
meta:
|
||||
id: fld_e7bcaad160254179a9c86e39a58c6893
|
||||
created: 1743683088154
|
||||
modified: 1743683090190
|
||||
sortKey: -1743683090140
|
||||
children:
|
||||
- url: "{{ _.base_url }}/api/auth/login"
|
||||
name: Login User
|
||||
meta:
|
||||
id: req_d48ab8553cff4eb486b816e064cf99a4
|
||||
created: 1743683199141
|
||||
modified: 1743683342872
|
||||
isPrivate: false
|
||||
sortKey: -1743683199141
|
||||
method: POST
|
||||
body:
|
||||
mimeType: application/json
|
||||
text: |-
|
||||
{
|
||||
"username": "testuser",
|
||||
"password": "testpass123"
|
||||
}
|
||||
headers:
|
||||
- name: Content-Type
|
||||
value: application/json
|
||||
- name: User-Agent
|
||||
value: insomnia/10.3.1
|
||||
settings:
|
||||
renderRequestBody: true
|
||||
encodeUrl: true
|
||||
followRedirects: global
|
||||
cookies:
|
||||
send: true
|
||||
store: true
|
||||
rebuildPath: true
|
||||
- url: "{{ _.base_url }}/api/users"
|
||||
name: Get Users
|
||||
meta:
|
||||
id: req_0393b8ff4ee1454daddacdda33fd33ea
|
||||
created: 1743683426423
|
||||
modified: 1743683632735
|
||||
isPrivate: false
|
||||
description: Retrieve all users from the system
|
||||
sortKey: -1743683429031
|
||||
method: GET
|
||||
headers:
|
||||
- name: Authorization
|
||||
value: Bearer {{ _.auth_token }}
|
||||
- name: User-Agent
|
||||
value: insomnia/10.3.1
|
||||
settings:
|
||||
renderRequestBody: true
|
||||
encodeUrl: true
|
||||
followRedirects: global
|
||||
cookies:
|
||||
send: true
|
||||
store: true
|
||||
rebuildPath: true
|
||||
- name: Data Management
|
||||
meta:
|
||||
id: fld_4736de73a1634b16960fa9e90d78f868
|
||||
created: 1743683403969
|
||||
modified: 1743683403969
|
||||
sortKey: -1743683403969
|
||||
children:
|
||||
- url: "{{ _.base_url }}/api/posts"
|
||||
name: Create Post
|
||||
meta:
|
||||
id: req_10db7ec1332d4444aa551e70a1bfae33
|
||||
created: 1743683795359
|
||||
modified: 1743683832200
|
||||
isPrivate: false
|
||||
sortKey: -1743683429131
|
||||
method: POST
|
||||
body:
|
||||
mimeType: application/json
|
||||
text: |-
|
||||
{
|
||||
"title": "Test Post",
|
||||
"content": "This is a test post content",
|
||||
"author": "Test Author"
|
||||
}
|
||||
headers:
|
||||
- name: Content-Type
|
||||
value: application/json
|
||||
- name: Authorization
|
||||
value: Bearer {{ _.auth_token }}
|
||||
- name: User-Agent
|
||||
value: insomnia/10.3.1
|
||||
settings:
|
||||
renderRequestBody: true
|
||||
encodeUrl: true
|
||||
followRedirects: global
|
||||
cookies:
|
||||
send: true
|
||||
store: true
|
||||
rebuildPath: true
|
||||
cookieJar:
|
||||
name: Default Jar
|
||||
meta:
|
||||
id: jar_25f97142fa796ae37f7f4937c0ebf3a07869d0a8
|
||||
created: 1743683067908
|
||||
modified: 1743683833282
|
||||
cookies: []
|
||||
environments:
|
||||
name: Base Environment
|
||||
meta:
|
||||
id: env_25f97142fa796ae37f7f4937c0ebf3a07869d0a8
|
||||
created: 1743683067895
|
||||
modified: 1743683476058
|
||||
isPrivate: false
|
||||
data:
|
||||
base_url: https://api.example.com
|
||||
auth_token: your_auth_token_here
|
||||
1
tests/import/test-data/invalid-json.json
Normal file
1
tests/import/test-data/invalid-json.json
Normal file
@@ -0,0 +1 @@
|
||||
{ "invalid": json syntax }
|
||||
1
tests/import/test-data/invalid.txt
Normal file
1
tests/import/test-data/invalid.txt
Normal file
@@ -0,0 +1 @@
|
||||
This is not a valid collection file
|
||||
374
tests/import/test-data/openapi-comprehensive.yaml
Normal file
374
tests/import/test-data/openapi-comprehensive.yaml
Normal file
@@ -0,0 +1,374 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Comprehensive API Test Collection
|
||||
description: A comprehensive API for testing OpenAPI v3 imports with various features
|
||||
version: 2.1.0
|
||||
contact:
|
||||
name: API Support
|
||||
email: support@example.com
|
||||
license:
|
||||
name: MIT
|
||||
url: https://opensource.org/licenses/MIT
|
||||
servers:
|
||||
- url: https://api.example.com/v1
|
||||
description: Production server
|
||||
- url: https://staging-api.example.com/v1
|
||||
description: Staging server
|
||||
- url: http://localhost:3000/v1
|
||||
description: Development server
|
||||
security:
|
||||
- bearerAuth: []
|
||||
- apiKey: []
|
||||
paths:
|
||||
/users:
|
||||
get:
|
||||
summary: Get all users
|
||||
description: Retrieve a paginated list of all users
|
||||
tags:
|
||||
- Users
|
||||
parameters:
|
||||
- name: page
|
||||
in: query
|
||||
description: Page number for pagination
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
default: 1
|
||||
- name: limit
|
||||
in: query
|
||||
description: Number of items per page
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
default: 20
|
||||
- name: filter
|
||||
in: query
|
||||
description: Filter users by name or email
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: List of users retrieved successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
users:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
pagination:
|
||||
$ref: '#/components/schemas/Pagination'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
post:
|
||||
summary: Create a new user
|
||||
description: Create a new user account
|
||||
tags:
|
||||
- Users
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateUserRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: User created successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'409':
|
||||
description: User already exists
|
||||
/users/{userId}:
|
||||
get:
|
||||
summary: Get user by ID
|
||||
description: Retrieve a specific user by their ID
|
||||
tags:
|
||||
- Users
|
||||
parameters:
|
||||
- name: userId
|
||||
in: path
|
||||
required: true
|
||||
description: The user ID
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'200':
|
||||
description: User retrieved successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
put:
|
||||
summary: Update user
|
||||
description: Update an existing user
|
||||
tags:
|
||||
- Users
|
||||
parameters:
|
||||
- name: userId
|
||||
in: path
|
||||
required: true
|
||||
description: The user ID
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UpdateUserRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: User updated successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
delete:
|
||||
summary: Delete user
|
||||
description: Delete a user account
|
||||
tags:
|
||||
- Users
|
||||
parameters:
|
||||
- name: userId
|
||||
in: path
|
||||
required: true
|
||||
description: The user ID
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'204':
|
||||
description: User deleted successfully
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
/auth/login:
|
||||
post:
|
||||
summary: User login
|
||||
description: Authenticate user and get access token
|
||||
tags:
|
||||
- Authentication
|
||||
security: [] # No security required for login
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- email
|
||||
- password
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
password:
|
||||
type: string
|
||||
minLength: 8
|
||||
responses:
|
||||
'200':
|
||||
description: Login successful
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
expiresIn:
|
||||
type: integer
|
||||
user:
|
||||
$ref: '#/components/schemas/User'
|
||||
'401':
|
||||
description: Invalid credentials
|
||||
/posts:
|
||||
get:
|
||||
summary: Get all posts
|
||||
description: Retrieve all blog posts
|
||||
tags:
|
||||
- Posts
|
||||
parameters:
|
||||
- name: author
|
||||
in: query
|
||||
description: Filter by author ID
|
||||
schema:
|
||||
type: string
|
||||
- name: category
|
||||
in: query
|
||||
description: Filter by category
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: List of posts
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Post'
|
||||
post:
|
||||
summary: Create a new post
|
||||
description: Create a new blog post
|
||||
tags:
|
||||
- Posts
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreatePostRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Post created successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Post'
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
apiKey:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: X-API-Key
|
||||
schemas:
|
||||
User:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
name:
|
||||
type: string
|
||||
avatar:
|
||||
type: string
|
||||
format: uri
|
||||
createdAt:
|
||||
type: string
|
||||
format: date-time
|
||||
updatedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
CreateUserRequest:
|
||||
type: object
|
||||
required:
|
||||
- email
|
||||
- name
|
||||
- password
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
name:
|
||||
type: string
|
||||
minLength: 2
|
||||
password:
|
||||
type: string
|
||||
minLength: 8
|
||||
avatar:
|
||||
type: string
|
||||
format: uri
|
||||
UpdateUserRequest:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
minLength: 2
|
||||
avatar:
|
||||
type: string
|
||||
format: uri
|
||||
Post:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
title:
|
||||
type: string
|
||||
content:
|
||||
type: string
|
||||
author:
|
||||
$ref: '#/components/schemas/User'
|
||||
category:
|
||||
type: string
|
||||
publishedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
createdAt:
|
||||
type: string
|
||||
format: date-time
|
||||
CreatePostRequest:
|
||||
type: object
|
||||
required:
|
||||
- title
|
||||
- content
|
||||
- category
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
minLength: 5
|
||||
content:
|
||||
type: string
|
||||
minLength: 10
|
||||
category:
|
||||
type: string
|
||||
Pagination:
|
||||
type: object
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
limit:
|
||||
type: integer
|
||||
total:
|
||||
type: integer
|
||||
totalPages:
|
||||
type: integer
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
code:
|
||||
type: integer
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
Unauthorized:
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
NotFound:
|
||||
description: Resource not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
16
tests/import/test-data/openapi-invalid-version.yaml
Normal file
16
tests/import/test-data/openapi-invalid-version.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
openapi: 2.0 # Invalid version - only v3 is supported
|
||||
info:
|
||||
title: Invalid OpenAPI Version
|
||||
description: This uses OpenAPI v2 which is not supported
|
||||
version: 1.0.0
|
||||
host: api.example.com
|
||||
basePath: /v1
|
||||
schemes:
|
||||
- https
|
||||
paths:
|
||||
/users:
|
||||
get:
|
||||
summary: Get users
|
||||
responses:
|
||||
'200':
|
||||
description: List of users
|
||||
16
tests/import/test-data/openapi-malformed.yaml
Normal file
16
tests/import/test-data/openapi-malformed.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Malformed OpenAPI
|
||||
version: 1.0.0
|
||||
paths:
|
||||
/test:
|
||||
get:
|
||||
summary: Test endpoint
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
# Missing closing quotes and malformed YAML
|
||||
'400':
|
||||
description: Bad request
|
||||
malformed: yaml here
|
||||
extra: indentation
|
||||
9
tests/import/test-data/openapi-missing-info.yaml
Normal file
9
tests/import/test-data/openapi-missing-info.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
openapi: 3.0.0
|
||||
# Missing required info section
|
||||
paths:
|
||||
/test:
|
||||
get:
|
||||
summary: Test endpoint
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
116
tests/import/test-data/openapi-simple.json
Normal file
116
tests/import/test-data/openapi-simple.json
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "Simple Test API",
|
||||
"description": "A simple API for basic OpenAPI testing",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://httpbin.org",
|
||||
"description": "HTTPBin test server"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/get": {
|
||||
"get": {
|
||||
"summary": "HTTP GET test",
|
||||
"description": "Test HTTP GET request",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"args": {
|
||||
"type": "object"
|
||||
},
|
||||
"headers": {
|
||||
"type": "object"
|
||||
},
|
||||
"origin": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/post": {
|
||||
"post": {
|
||||
"summary": "HTTP POST test",
|
||||
"description": "Test HTTP POST request",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"json": {
|
||||
"type": "object"
|
||||
},
|
||||
"origin": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/status/{code}": {
|
||||
"get": {
|
||||
"summary": "Return status code",
|
||||
"description": "Return a specific HTTP status code",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "code",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "HTTP status code to return",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"minimum": 100,
|
||||
"maximum": 599
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "Returns the specified status code"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
tests/import/test-data/postman-invalid-missing-info.json
Normal file
11
tests/import/test-data/postman-invalid-missing-info.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"item": [
|
||||
{
|
||||
"name": "Request without info",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "https://example.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
7
tests/import/test-data/postman-invalid-schema.json
Normal file
7
tests/import/test-data/postman-invalid-schema.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "Invalid Schema Collection",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v999.0.0/collection.json"
|
||||
},
|
||||
"item": []
|
||||
}
|
||||
6
tests/import/test-data/postman-malformed.json
Normal file
6
tests/import/test-data/postman-malformed.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "Malformed Collection"
|
||||
},
|
||||
"item": "this should be an array, not a string"
|
||||
}
|
||||
17
tests/import/test-data/postman-v20.json
Normal file
17
tests/import/test-data/postman-v20.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "Postman v2.0 Collection",
|
||||
"description": "Test collection using Postman Collection Format v2.0",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Get Posts",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": "https://jsonplaceholder.typicode.com/posts"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
64
tests/import/test-data/postman-v21.json
Normal file
64
tests/import/test-data/postman-v21.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "Postman v2.1 Collection",
|
||||
"description": "Test collection using Postman Collection Format v2.1",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
"_postman_id": "12345678-1234-1234-1234-123456789012"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Get Users",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{token}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/users",
|
||||
"host": ["{{baseUrl}}"],
|
||||
"path": ["users"],
|
||||
"query": [
|
||||
{
|
||||
"key": "page",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Create User",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/users",
|
||||
"host": ["{{baseUrl}}"],
|
||||
"path": ["users"]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "baseUrl",
|
||||
"value": "https://api.example.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
25
tests/preferences/support-links.spec.js
Normal file
25
tests/preferences/support-links.spec.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
|
||||
test('Should verify all support links with correct URL in preference > Support tab', async ({ page }) => {
|
||||
// Open Preferences
|
||||
await page.getByLabel('Open Preferences').click();
|
||||
|
||||
// Go to Support tab
|
||||
await page.getByRole('tab', { name: 'Support' }).click();
|
||||
|
||||
// Verify all support links with correct URL
|
||||
const locator_twitter = page.getByRole('link', { name: 'Twitter' });
|
||||
expect(await locator_twitter.getAttribute('href')).toEqual('https://twitter.com/use_bruno');
|
||||
|
||||
const locator_github = page.getByRole('link', { name: 'GitHub', exact: true });
|
||||
expect(await locator_github.getAttribute('href')).toEqual('https://github.com/usebruno/bruno');
|
||||
|
||||
const locator_discord = page.getByRole('link', { name: 'Discord', exact: true });
|
||||
expect(await locator_discord.getAttribute('href')).toEqual('https://discord.com/invite/KgcZUncpjq');
|
||||
|
||||
const locator_reportissues = page.getByRole('link', { name: 'Report Issues', exact: true });
|
||||
expect(await locator_reportissues.getAttribute('href')).toEqual('https://github.com/usebruno/bruno/issues');
|
||||
|
||||
const locator_documentation = page.getByRole('link', { name: 'Documentation', exact: true });
|
||||
expect(await locator_documentation.getAttribute('href')).toEqual('https://docs.usebruno.com');
|
||||
});
|
||||
49
tests/runner/collection-run.ts
Normal file
49
tests/runner/collection-run.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
|
||||
test.describe.parallel('Collection Run', () => {
|
||||
test('Run bruno-testbench in Developer Mode', async ({ pageWithUserData: page }) => {
|
||||
test.setTimeout(2 * 60 * 1000);
|
||||
|
||||
await page.getByText('bruno-testbench').click();
|
||||
await page.getByLabel('Developer Mode(use only if').check();
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
await page.locator('.environment-selector').nth(1).click();
|
||||
await page.locator('.dropdown-item').getByText('Prod').click();
|
||||
await page.locator('.collection-actions').hover();
|
||||
await page.locator('.collection-actions .icon').click();
|
||||
await page.getByText('Run', { exact: true }).click();
|
||||
await page.getByRole('button', { name: 'Run Collection' }).click();
|
||||
await page.getByRole('button', { name: 'Run Again' }).waitFor({ timeout: 2 * 60 * 1000 });
|
||||
|
||||
const result = await page.getByText('Total Requests: ').innerText();
|
||||
const [totalRequests, passed, failed, skipped] = result
|
||||
.match(/Total Requests: (\d+), Passed: (\d+), Failed: (\d+), Skipped: (\d+)/)
|
||||
.slice(1);
|
||||
|
||||
await expect(parseInt(failed)).toBe(0);
|
||||
await expect(parseInt(passed)).toBe(parseInt(totalRequests) - parseInt(skipped) - parseInt(failed));
|
||||
});
|
||||
|
||||
test.fixme('Run bruno-testbench in Safe Mode', async ({ pageWithUserData: page }) => {
|
||||
test.setTimeout(2 * 60 * 1000);
|
||||
|
||||
await page.getByText('bruno-testbench').click();
|
||||
await page.getByLabel('Safe Mode').check();
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
await page.locator('.environment-selector').nth(1).click();
|
||||
await page.locator('.dropdown-item').getByText('Prod').click();
|
||||
await page.locator('.collection-actions').hover();
|
||||
await page.locator('.collection-actions .icon').click();
|
||||
await page.getByText('Run', { exact: true }).click();
|
||||
await page.getByRole('button', { name: 'Run Collection' }).click();
|
||||
await page.getByRole('button', { name: 'Run Again' }).waitFor({ timeout: 2 * 60 * 1000 });
|
||||
|
||||
const result = await page.getByText('Total Requests: ').innerText();
|
||||
const [totalRequests, passed, failed, skipped] = result
|
||||
.match(/Total Requests: (\d+), Passed: (\d+), Failed: (\d+), Skipped: (\d+)/)
|
||||
.slice(1);
|
||||
|
||||
await expect(parseInt(failed)).toBe(0);
|
||||
await expect(parseInt(passed)).toBe(parseInt(totalRequests) - parseInt(skipped) - parseInt(failed));
|
||||
});
|
||||
});
|
||||
4
tests/runner/init-user-data/preferences.json
Normal file
4
tests/runner/init-user-data/preferences.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"maximized": true,
|
||||
"lastOpenedCollections": ["{{projectRoot}}/packages/bruno-tests/collection"]
|
||||
}
|
||||
5
tests/start/app-open.spec.ts
Normal file
5
tests/start/app-open.spec.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
|
||||
test('Check if the logo on top left is visible', async ({ page }) => {
|
||||
await expect(page.getByRole('button', { name: 'bruno' })).toBeVisible();
|
||||
});
|
||||
Reference in New Issue
Block a user