Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions packages/bruno-app/src/components/RequestTabs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import RequestTab from './RequestTab';
import StyledWrapper from './StyledWrapper';
import DraggableTab from './DraggableTab';
import CreateUntitledRequest from 'components/CreateUntitledRequest';
Comment thread
sid-bruno marked this conversation as resolved.
import { IconPlus } from '@tabler/icons';

const RequestTabs = () => {
const dispatch = useDispatch();
Expand Down Expand Up @@ -174,14 +175,15 @@ const RequestTabs = () => {
</li>
) : null}
<div className="flex items-center cursor-pointer short-tab">

{activeCollection && (
<CreateUntitledRequest
collectionUid={activeCollection.uid}
itemUid={null}
placement="bottom-start"
/>
)}
{
activeCollection && (
<IconPlus
size={18}
strokeWidth={1.5}
onClick={() => setNewRequestModalOpen(true)}
/>
)
}
</div>
{/* Moved to post mvp */}
{/* <li className="select-none new-tab choose-request">
Expand Down
15 changes: 9 additions & 6 deletions tests/collection/create/create-collection.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test, expect } from '../../../playwright';
import { closeAllCollections, createUntitledRequest } from '../../utils/page';
import { closeAllCollections, createRequest } from '../../utils/page';

test.describe('Create collection', () => {
test.afterEach(async ({ page }) => {
Expand All @@ -8,20 +8,23 @@ test.describe('Create collection', () => {
});

test('Create collection and add a simple HTTP request', async ({ page, createTmpDir }) => {
const collectionName = 'test-collection';
const requestName = 'ping';

await page.getByTestId('collections-header-add-menu').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').click();
await page.getByLabel('Name').fill('test-collection');
await page.getByLabel('Name').fill(collectionName);
await page.getByLabel('Name').press('Tab');
const locationInput = page.locator('.bruno-modal').getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('test-collection'));
await locationInput.fill(await createTmpDir(collectionName));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();
await page.locator('#sidebar-collection-name').filter({ hasText: 'test-collection' }).click();
await page.locator('#sidebar-collection-name').filter({ hasText: collectionName }).click();

// Create a new request using the new dropdown flow
await createUntitledRequest(page, { requestType: 'HTTP' });
// Create a new request using the dialog/modal flow
await createRequest(page, requestName, collectionName);

// Set the URL
await page.locator('#request-url .CodeMirror').click();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test, expect } from '../../../playwright';
import { closeAllCollections, createCollection, createUntitledRequest } from '../../utils/page';
import { closeAllCollections, createCollection, createRequest } from '../../utils/page';

test.describe('Cross-Collection Drag and Drop', () => {
test.afterEach(async ({ page }) => {
Expand All @@ -8,18 +8,13 @@ test.describe('Cross-Collection Drag and Drop', () => {
});

test('Verify request drag and drop', async ({ page, createTmpDir }) => {
const requestName = 'drag-drop-request';

// Create first collection - open with sandbox mode
await createCollection(page, 'source-collection', await createTmpDir('source-collection'));

// Create a request in the first collection using the new dropdown flow
await createUntitledRequest(page, { requestType: 'HTTP' });

// Set the URL
await page.locator('#request-url .CodeMirror').click();
await page.locator('#request-url').locator('textarea').fill('https://echo.usebruno.com');
await page.locator('#send-request').getByTitle('Save Request').click();

await expect(page.locator('.item-name').filter({ hasText: /^Untitled/ })).toBeVisible();
// Create a request in the first collection using the dialog/modal flow
await createRequest(page, requestName, 'source-collection', { url: 'https://echo.usebruno.com' });

// Create second collection - open with sandbox mode
await createCollection(page, 'target-collection', await createTmpDir('target-collection'));
Expand All @@ -28,7 +23,11 @@ test.describe('Cross-Collection Drag and Drop', () => {
await expect(page.locator('#sidebar-collection-name').filter({ hasText: 'target-collection' })).toBeVisible();

// Locate the request in source collection
const sourceRequest = page.locator('.item-name').filter({ hasText: /^Untitled/ }).first();
const sourceCollectionContainer = page
.locator('.collection-name')
.filter({ hasText: 'source-collection' })
.locator('..');
const sourceRequest = sourceCollectionContainer.locator('.collection-item-name').filter({ hasText: requestName }).first();
await expect(sourceRequest).toBeVisible();

// Locate the target collection area (the collection name element)
Expand All @@ -44,51 +43,44 @@ test.describe('Cross-Collection Drag and Drop', () => {
.locator('.collection-name')
.filter({ hasText: 'target-collection' })
.locator('..');
await expect(
targetCollectionContainer.locator('.item-name').filter({ hasText: /^Untitled/ })
).toBeVisible();
await expect(targetCollectionContainer.locator('.collection-item-name').filter({ hasText: requestName })).toBeVisible();

// Verify the request is no longer in the source collection
const sourceCollectionContainer = page
.locator('.collection-name')
.filter({ hasText: 'source-collection' })
.locator('..');
await expect(
sourceCollectionContainer.locator('.item-name').filter({ hasText: /^Untitled/ })
).not.toBeVisible();
await page.locator('#sidebar-collection-name').filter({ hasText: 'source-collection' }).click();
await expect(sourceCollectionContainer.locator('.collection-item-name').filter({ hasText: requestName })).toHaveCount(0);
});

test('Expected to show error toast message, when duplicate request found in drop location', async ({
page,
createTmpDir
}) => {
const requestName = 'duplicate-request';

// Create first collection (source-collection)
await createCollection(page, 'source-collection', await createTmpDir('source-collection'));

// Create a request in the first collection using the new dropdown flow
await createUntitledRequest(page, { requestType: 'HTTP' });

// Set the URL
await page.locator('#request-url .CodeMirror').click();
await page.locator('#request-url').locator('textarea').fill('https://echo.usebruno.com');
await page.locator('#send-request').getByTitle('Save Request').click();

// check if untitled request is created and visible in sidebar
await expect(page.locator('.item-name').filter({ hasText: /^Untitled/ })).toBeVisible();
// Create a request in the first collection using the dialog/modal flow
await createRequest(page, requestName, 'source-collection', { url: 'https://echo.usebruno.com' });

// Create second collection (target-collection)
await createCollection(page, 'target-collection', await createTmpDir('target-collection'));

// Create a request in the target collection using the new dropdown flow
await createUntitledRequest(page, { requestType: 'HTTP' });

// Set the URL
await page.locator('#request-url .CodeMirror').click();
await page.locator('#request-url').locator('textarea').fill('https://echo.usebruno.com');
await page.locator('#send-request').getByTitle('Save Request').click();
// Create a request with the same name in the target collection using the dialog/modal flow
await createRequest(page, requestName, 'target-collection', { url: 'https://echo.usebruno.com' });

// Go back to source collection to drag the request
const sourceRequest = page.locator('.item-name').filter({ hasText: /^Untitled/ }).first();
await page.locator('#sidebar-collection-name').filter({ hasText: 'source-collection' }).click();

const sourceCollectionContainer = page
.locator('.collection-name')
.filter({ hasText: 'source-collection' })
.locator('..');
const targetCollectionContainer = page
.locator('.collection-name')
.filter({ hasText: 'target-collection' })
.locator('..');

const sourceRequest = sourceCollectionContainer.locator('.collection-item-name').filter({ hasText: requestName }).first();
await expect(sourceRequest).toBeVisible();

// Locate the target collection area
Expand All @@ -102,20 +94,8 @@ test.describe('Cross-Collection Drag and Drop', () => {
await expect(page.getByText(/Error: Cannot copy.*already exists/i)).toBeVisible();

// source and target collection request should remain unchanged
const targetCollectionContainer = page
.locator('.collection-name')
.filter({ hasText: 'target-collection' })
.locator('..');
await expect(
targetCollectionContainer.locator('.item-name').filter({ hasText: /^Untitled/ })
).toBeVisible();

const sourceCollectionContainer = page
.locator('.collection-name')
.filter({ hasText: 'source-collection' })
.locator('..');
await expect(
sourceCollectionContainer.locator('.item-name').filter({ hasText: /^Untitled/ })
).toBeVisible();
await expect(sourceCollectionContainer.locator('.collection-item-name').filter({ hasText: requestName })).toBeVisible();
await page.locator('#sidebar-collection-name').filter({ hasText: 'target-collection' }).click();
await expect(targetCollectionContainer.locator('.collection-item-name').filter({ hasText: requestName })).toBeVisible();
});
});
67 changes: 33 additions & 34 deletions tests/collection/moving-requests/tag-persistence.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test, expect } from '../../../playwright';
import { closeAllCollections, createUntitledRequest, selectRequestPaneTab } from '../../utils/page';
import { closeAllCollections, createRequest, selectRequestPaneTab } from '../../utils/page';
import { buildCommonLocators } from '../../utils/page/locators';

test.describe('Tag persistence', () => {
Expand All @@ -10,43 +10,40 @@ test.describe('Tag persistence', () => {

test('Verify tag persistence while moving requests within a collection', async ({ page, createTmpDir }) => {
const locators = buildCommonLocators(page);
const collectionName = 'test-collection';
const requestUrl = 'https://httpfaker.org/api/echo';
const tagName = 'smoke';

// Create first collection - click plus icon button to open dropdown
await locators.plusMenu.button().click();
await locators.plusMenu.createCollection().click();
await page.getByLabel('Name').fill('test-collection');
await page.getByLabel('Name').fill(collectionName);
const locationInput = locators.modal.byTitle('Create Collection').getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('test-collection'));
await locationInput.fill(await createTmpDir(collectionName));
}
await locators.modal.button('Create').click();
await locators.sidebar.collection('test-collection').click();
await locators.sidebar.collection(collectionName).click();
await page.waitForTimeout(1000);
// Create three requests, each with URL and tag (auto-saved after each is completely created)
// The createUntitledRequest function now waits for each request to be fully created
// before returning, ensuring unique names are generated
await createUntitledRequest(page, {
requestType: 'HTTP',
url: 'https://httpfaker.org/api/echo',
tag: 'smoke'
});
await createUntitledRequest(page, {
requestType: 'HTTP',
url: 'https://httpfaker.org/api/echo',
tag: 'smoke'
});
await createUntitledRequest(page, {
requestType: 'HTTP',
url: 'https://httpfaker.org/api/echo',
tag: 'smoke'
});

// Wait for all 3 requests to be visible in the sidebar
const untitledRequests = page.locator('.item-name').filter({ hasText: /^Untitled/ });
await expect(untitledRequests).toHaveCount(3);
// Create three requests via the dialog/modal flow, then add a tag to each
const requestNames = ['request-1', 'request-2', 'request-3'];
for (const requestName of requestNames) {
await createRequest(page, requestName, collectionName, { url: requestUrl });
await locators.sidebar.request(requestName).click();
await locators.tabs.requestTab(requestName).waitFor({ state: 'visible' });
await selectRequestPaneTab(page, 'Settings');
await page.waitForTimeout(200);
await locators.tags.input().fill(tagName);
await locators.tags.input().press('Enter');
await page.waitForTimeout(200);
await expect(locators.tags.item(tagName)).toBeVisible();
await page.keyboard.press('Meta+s');
Comment thread
sid-bruno marked this conversation as resolved.
await page.waitForTimeout(200);
}

// Move the last untitled request to just above the first untitled request within the same collection
const r3Request = untitledRequests.nth(2); // Third request (0-indexed)
const r1Request = untitledRequests.first(); // First request
// Move the last request to just above the first request within the same collection
const r3Request = locators.sidebar.request('request-3');
const r1Request = locators.sidebar.request('request-1');

await expect(r3Request).toBeVisible();
await expect(r1Request).toBeVisible();
Expand All @@ -57,15 +54,17 @@ test.describe('Tag persistence', () => {
});

// Verify the requests are still in the collection
await expect(untitledRequests).toHaveCount(3);
for (const requestName of requestNames) {
await expect(locators.sidebar.request(requestName)).toBeVisible();
}

// Click on the moved request (now first) to verify the tag persisted after the move
await untitledRequests.first().click();
await locators.tabs.activeRequestTab().waitFor({ state: 'visible' });
// Click on the moved request to verify the tag persisted after the move
await r3Request.click();
await locators.tabs.requestTab('request-3').waitFor({ state: 'visible' });
await selectRequestPaneTab(page, 'Settings');
await page.waitForTimeout(200);
// Verify the tag is still present after the move
await expect(locators.tags.item('smoke')).toBeVisible();
await expect(locators.tags.item(tagName)).toBeVisible();
});

test('verify tag persistence while moving requests between folders', async ({ page, createTmpDir }) => {
Expand Down
46 changes: 23 additions & 23 deletions tests/request/encoding/curl-encoding.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test, expect } from '../../../playwright';
import { closeAllCollections, createUntitledRequest } from '../../utils/page';
import { closeAllCollections, createRequest } from '../../utils/page';

test.describe('Code Generation URL Encoding', () => {
test.afterEach(async ({ page }) => {
Expand All @@ -18,27 +18,27 @@ test.describe('Code Generation URL Encoding', () => {
page,
createTmpDir
}) => {
const collectionName = 'unencoded-test-collection';
const requestName = 'curl-encoding-unencoded';

// Use plus icon button in new workspace UI
await page.getByTestId('collections-header-add-menu').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').fill('unencoded-test-collection');
await page.getByLabel('Name').fill(collectionName);
const locationInput = page.getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('unencoded-test-collection'));
await locationInput.fill(await createTmpDir(collectionName));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();

await expect(page.locator('#sidebar-collection-name').filter({ hasText: 'unencoded-test-collection' })).toBeVisible();
await page.locator('#sidebar-collection-name').filter({ hasText: 'unencoded-test-collection' }).click();
await expect(page.locator('#sidebar-collection-name').filter({ hasText: collectionName })).toBeVisible();
await page.locator('#sidebar-collection-name').filter({ hasText: collectionName }).click();

// Create a new request using the new dropdown flow
await createUntitledRequest(page, {
requestType: 'HTTP',
url: 'http://base.source?name=John Doe'
});
// Create a new request using the dialog/modal flow
await createRequest(page, requestName, collectionName, { url: 'http://base.source?name=John Doe' });

// Find the untitled request and click on it
await page.locator('.item-name').filter({ hasText: /^Untitled/ }).first().click();
// Click the request in the sidebar
await page.locator('.collection-item-name').filter({ hasText: requestName }).first().click();

await page.locator('#send-request .infotip').first().click();

Expand All @@ -61,27 +61,27 @@ test.describe('Code Generation URL Encoding', () => {
page,
createTmpDir
}) => {
const collectionName = 'encoded-test-collection';
const requestName = 'curl-encoding-encoded';

// Use plus icon button in new workspace UI
await page.getByTestId('collections-header-add-menu').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').fill('encoded-test-collection');
await page.getByLabel('Name').fill(collectionName);
const locationInput = page.getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('encoded-test-collection'));
await locationInput.fill(await createTmpDir(collectionName));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();

await expect(page.locator('#sidebar-collection-name').filter({ hasText: 'encoded-test-collection' })).toBeVisible();
await page.locator('#sidebar-collection-name').filter({ hasText: 'encoded-test-collection' }).click();
await expect(page.locator('#sidebar-collection-name').filter({ hasText: collectionName })).toBeVisible();
await page.locator('#sidebar-collection-name').filter({ hasText: collectionName }).click();

// Create a new request using the new dropdown flow
await createUntitledRequest(page, {
requestType: 'HTTP',
url: 'http://base.source?name=John%20Doe'
});
// Create a new request using the dialog/modal flow
await createRequest(page, requestName, collectionName, { url: 'http://base.source?name=John%20Doe' });

// Find the untitled request and click on it
await page.locator('.item-name').filter({ hasText: /^Untitled/ }).first().click();
// Click the request in the sidebar
await page.locator('.collection-item-name').filter({ hasText: requestName }).first().click();

await page.locator('#send-request .infotip').first().click();

Expand Down
Loading
Loading