|
| 1 | +import { expect } from '@playwright/test'; |
| 2 | + |
| 3 | +import { loadFixture } from '../../playwright/paths'; |
| 4 | +import { test } from '../../playwright/test'; |
| 5 | + |
| 6 | +/** |
| 7 | + * Core Workflow Tests |
| 8 | + * |
| 9 | + * Covers the primary end-to-end Insomnia workflows: |
| 10 | + * 1. Sending a GET request with environment-variable URL substitution |
| 11 | + * 2. Creating a resource via POST and verifying the 201 response |
| 12 | + * 3. Full CRUD chain: POST to create → after-response script captures ID → GET retrieves item |
| 13 | + * 4. Custom request headers propagated and reflected in an echo response |
| 14 | + * 5. Basic authentication applied to a protected endpoint |
| 15 | + * 6. Creating a new HTTP request manually from the UI and sending it |
| 16 | + * |
| 17 | + * Mock server endpoints used (all in packages/insomnia-smoke-test/server/): |
| 18 | + * GET /pets/:id → 200 { id } |
| 19 | + * POST /simple-crud → 201 { id, ...body } |
| 20 | + * GET /simple-crud/:id → 200 { id, ...body } | 404 |
| 21 | + * POST /echo → 200 { method, headers, data, cookies } |
| 22 | + * GET /auth/basic → 200 (requires Basic user:pass) |
| 23 | + */ |
| 24 | + |
| 25 | +test.describe('Core Workflow', () => { |
| 26 | + test.slow(process.platform === 'darwin' || process.platform === 'win32', 'Slow app start on these platforms'); |
| 27 | + |
| 28 | + test.beforeEach(async ({ app, page }) => { |
| 29 | + const text = await loadFixture('core-workflow.yaml'); |
| 30 | + await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text); |
| 31 | + |
| 32 | + await page.getByLabel('Import').click(); |
| 33 | + await page.locator('[data-test-id="import-from-clipboard"]').click(); |
| 34 | + await page.getByRole('button', { name: 'Scan' }).click(); |
| 35 | + await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click(); |
| 36 | + }); |
| 37 | + |
| 38 | + // ─── 1. GET with environment-variable substitution ──────────────────────── |
| 39 | + |
| 40 | + test('sends GET request with env var substitution and verifies JSON response', async ({ page }) => { |
| 41 | + const statusTag = page.locator('[data-testid="response-status-tag"]:visible'); |
| 42 | + const responsePane = page.getByTestId('response-pane'); |
| 43 | + |
| 44 | + // Select the request and send it |
| 45 | + await page.getByLabel('Request Collection').getByTestId('get pet by id').press('Enter'); |
| 46 | + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); |
| 47 | + |
| 48 | + // Status: 200 OK |
| 49 | + await expect.soft(statusTag).toContainText('200 OK'); |
| 50 | + |
| 51 | + // Body: { "id": "42" } — pet_id env var resolved to "42" |
| 52 | + await expect.soft(responsePane).toContainText('"id"'); |
| 53 | + await expect.soft(responsePane).toContainText('"42"'); |
| 54 | + |
| 55 | + // Response Headers: content-type should be application/json |
| 56 | + await responsePane.getByRole('tab', { name: 'Headers' }).click(); |
| 57 | + await expect.soft(responsePane).toContainText('content-type'); |
| 58 | + }); |
| 59 | + |
| 60 | + // ─── 2. POST → 201 Created ──────────────────────────────────────────────── |
| 61 | + |
| 62 | + test('creates resource via POST and verifies 201 Created with body', async ({ page }) => { |
| 63 | + const statusTag = page.locator('[data-testid="response-status-tag"]:visible'); |
| 64 | + const responsePane = page.getByTestId('response-pane'); |
| 65 | + |
| 66 | + await page.getByLabel('Request Collection').getByTestId('create item').press('Enter'); |
| 67 | + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); |
| 68 | + |
| 69 | + // Status: 201 Created |
| 70 | + await expect.soft(statusTag).toContainText('201'); |
| 71 | + |
| 72 | + // Body includes the server-assigned id and the payload we sent |
| 73 | + await expect.soft(responsePane).toContainText('"id"'); |
| 74 | + await expect.soft(responsePane).toContainText('"Widget"'); |
| 75 | + await expect.soft(responsePane).toContainText('9.99'); |
| 76 | + |
| 77 | + // After-response script assertions are visible in the Tests tab |
| 78 | + await responsePane.getByRole('tab', { name: 'Tests' }).click(); |
| 79 | + const testRows = page.getByTestId('test-result-row'); |
| 80 | + await expect.soft(testRows.nth(0)).toContainText('PASS'); |
| 81 | + await expect.soft(testRows.nth(1)).toContainText('PASS'); |
| 82 | + }); |
| 83 | + |
| 84 | + // ─── 3. Full CRUD chain: POST create → GET retrieve ─────────────────────── |
| 85 | + |
| 86 | + test('performs full CRUD workflow: creates then retrieves resource', async ({ page }) => { |
| 87 | + const statusTag = page.locator('[data-testid="response-status-tag"]:visible'); |
| 88 | + const responsePane = page.getByTestId('response-pane'); |
| 89 | + |
| 90 | + // Step 1: Create – after-response script sets item_id in the environment |
| 91 | + await page.getByLabel('Request Collection').getByTestId('create item').press('Enter'); |
| 92 | + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); |
| 93 | + await expect.soft(statusTag).toContainText('201'); |
| 94 | + |
| 95 | + // Step 2: Retrieve – URL uses {{_.item_id}} injected by the script above |
| 96 | + await page.getByLabel('Request Collection').getByTestId('get created item').press('Enter'); |
| 97 | + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); |
| 98 | + |
| 99 | + // Status: 200 OK |
| 100 | + await expect.soft(statusTag).toContainText('200 OK'); |
| 101 | + |
| 102 | + // Body must contain the data we originally POSTed |
| 103 | + await expect.soft(responsePane).toContainText('"Widget"'); |
| 104 | + await expect.soft(responsePane).toContainText('9.99'); |
| 105 | + }); |
| 106 | + |
| 107 | + // ─── 4. Custom request headers reflected in echo response ───────────────── |
| 108 | + |
| 109 | + test('sends POST with custom headers and verifies echo response', async ({ page }) => { |
| 110 | + const statusTag = page.locator('[data-testid="response-status-tag"]:visible'); |
| 111 | + const responsePane = page.getByTestId('response-pane'); |
| 112 | + |
| 113 | + await page.getByLabel('Request Collection').getByTestId('echo with custom header').press('Enter'); |
| 114 | + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); |
| 115 | + |
| 116 | + // Status: 200 OK |
| 117 | + await expect.soft(statusTag).toContainText('200 OK'); |
| 118 | + |
| 119 | + // Echo server mirrors the HTTP method back in the body |
| 120 | + await expect.soft(responsePane).toContainText('"POST"'); |
| 121 | + |
| 122 | + // Our custom header value must appear in the echoed headers object |
| 123 | + await expect.soft(responsePane).toContainText('insomnia-rocks'); |
| 124 | + |
| 125 | + // The request body is also echoed under the "data" key |
| 126 | + await expect.soft(responsePane).toContainText('"workflow"'); |
| 127 | + }); |
| 128 | + |
| 129 | + // ─── 5. Basic authentication ────────────────────────────────────────────── |
| 130 | + |
| 131 | + test('sends authenticated request and verifies 200 OK', async ({ page }) => { |
| 132 | + const statusTag = page.locator('[data-testid="response-status-tag"]:visible'); |
| 133 | + |
| 134 | + await page.getByLabel('Request Collection').getByTestId('authenticated request').press('Enter'); |
| 135 | + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); |
| 136 | + |
| 137 | + // The basic-auth endpoint returns 200 only when credentials are valid |
| 138 | + await expect.soft(statusTag).toContainText('200 OK'); |
| 139 | + }); |
| 140 | + |
| 141 | + // ─── 6. Create new HTTP request from scratch via the UI ─────────────────── |
| 142 | + |
| 143 | + test('creates a new HTTP request from the UI, sets a URL, and sends it', async ({ page }) => { |
| 144 | + const statusTag = page.locator('[data-testid="response-status-tag"]:visible'); |
| 145 | + const responsePane = page.getByTestId('response-pane'); |
| 146 | + |
| 147 | + // Create a new blank HTTP request inside the collection |
| 148 | + await page.getByLabel('Create in collection').click(); |
| 149 | + await page.getByRole('menuitemradio', { name: 'Http Request' }).click(); |
| 150 | + |
| 151 | + // The new request row should be selected and the request pane visible |
| 152 | + const newRequest = page.getByLabel('Request Collection').getByRole('row', { name: 'New Request' }).first(); |
| 153 | + await expect.soft(newRequest.locator('[data-selected="true"]').first()).toBeVisible(); |
| 154 | + |
| 155 | + // Enter a URL in the URL bar (OneLineEditor at the top of the request pane) |
| 156 | + const urlBar = page.getByTestId('request-pane').getByTestId('OneLineEditor').first().getByRole('textbox'); |
| 157 | + await urlBar.click(); |
| 158 | + await page.keyboard.type('http://127.0.0.1:4010/pets/99'); |
| 159 | + await page.keyboard.press('Tab'); |
| 160 | + |
| 161 | + // Send the request |
| 162 | + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); |
| 163 | + |
| 164 | + // Status: 200 OK |
| 165 | + await expect.soft(statusTag).toContainText('200 OK'); |
| 166 | + |
| 167 | + // The mock server echoes back the path parameter as the id |
| 168 | + await expect.soft(responsePane).toContainText('"id"'); |
| 169 | + await expect.soft(responsePane).toContainText('"99"'); |
| 170 | + }); |
| 171 | + |
| 172 | + // ─── 7. Environment switching changes the resolved URL ──────────────────── |
| 173 | + |
| 174 | + test('switches to Staging environment and sends GET with different pet_id', async ({ page }) => { |
| 175 | + const statusTag = page.locator('[data-testid="response-status-tag"]:visible'); |
| 176 | + const responsePane = page.getByTestId('response-pane'); |
| 177 | + |
| 178 | + // Switch the active sub-environment to "Staging" (pet_id = "1") |
| 179 | + await page.getByRole('button', { name: 'Manage Environments' }).click(); |
| 180 | + await page.getByRole('option', { name: 'Staging' }).press('Enter'); |
| 181 | + await page.getByRole('option', { name: 'Staging' }).press('Escape'); |
| 182 | + |
| 183 | + // Send the same GET /pets/{{pet_id}} request |
| 184 | + await page.getByLabel('Request Collection').getByTestId('get pet by id').press('Enter'); |
| 185 | + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); |
| 186 | + |
| 187 | + // Status: 200 OK |
| 188 | + await expect.soft(statusTag).toContainText('200 OK'); |
| 189 | + |
| 190 | + // pet_id from the Staging env is "1", not the base env "42" |
| 191 | + await expect.soft(responsePane).toContainText('"1"'); |
| 192 | + }); |
| 193 | +}); |
0 commit comments