fix: update how ky handle error (#34735)

This commit is contained in:
Stephen Zhou
2026-04-08 18:38:33 +08:00
committed by GitHub
parent 9948a51b14
commit 63bfba0bdb
7 changed files with 62 additions and 12 deletions

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
ROOT="$(dirname "$SCRIPT_DIR")"
cd "$ROOT/docker"
docker compose --env-file middleware.env -f docker-compose.middleware.yaml -p dify up -d
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
ROOT="$(dirname "$SCRIPT_DIR")"
cd "$ROOT/docker"
docker compose --env-file middleware.env -f docker-compose.middleware.yaml -p dify up -d

View File

@@ -0,0 +1,7 @@
@smoke @unauthenticated
Feature: Unauthenticated app console entry
Scenario: Redirect to the sign-in page when opening the apps console without logging in
Given I am not signed in
When I open the apps console
Then I should be redirected to the signin page
And I should see the "Sign in" button

View File

@@ -9,3 +9,10 @@ Given('I am signed in as the default E2E admin', async function (this: DifyWorld
'text/plain',
)
})
Given('I am not signed in', async function (this: DifyWorld) {
this.attach(
'Using a clean browser context without the shared authenticated storage state.',
'text/plain',
)
})

View File

@@ -10,6 +10,10 @@ Then('I should stay on the apps console', async function (this: DifyWorld) {
await expect(this.getPage()).toHaveURL(/\/apps(?:\?.*)?$/)
})
Then('I should be redirected to the signin page', async function (this: DifyWorld) {
await expect(this.getPage()).toHaveURL(/\/signin(?:\?.*)?$/)
})
Then('I should see the {string} button', async function (this: DifyWorld, label: string) {
await expect(this.getPage().getByRole('button', { name: label })).toBeVisible()
})

View File

@@ -46,7 +46,11 @@ BeforeAll(async () => {
Before(async function (this: DifyWorld, { pickle }) {
if (!browser) throw new Error('Shared Playwright browser is not available.')
await this.startAuthenticatedSession(browser)
const isUnauthenticatedScenario = pickle.tags.some((tag) => tag.name === '@unauthenticated')
if (isUnauthenticatedScenario) await this.startUnauthenticatedSession(browser)
else await this.startAuthenticatedSession(browser)
this.scenarioStartedAt = Date.now()
const tags = pickle.tags.map((tag) => tag.name).join(' ')

View File

@@ -25,12 +25,12 @@ export class DifyWorld extends World {
this.pageErrors = []
}
async startAuthenticatedSession(browser: Browser) {
async startSession(browser: Browser, authenticated: boolean) {
this.resetScenarioState()
this.context = await browser.newContext({
baseURL,
locale: defaultLocale,
storageState: authStatePath,
...(authenticated ? { storageState: authStatePath } : {}),
})
this.context.setDefaultTimeout(30_000)
this.page = await this.context.newPage()
@@ -44,6 +44,14 @@ export class DifyWorld extends World {
})
}
async startAuthenticatedSession(browser: Browser) {
await this.startSession(browser, true)
}
async startUnauthenticatedSession(browser: Browser) {
await this.startSession(browser, false)
}
getPage() {
if (!this.page) throw new Error('Playwright page has not been initialized for this scenario.')

View File

@@ -38,6 +38,26 @@ export type ResponseError = {
status: number
}
const createResponseFromHTTPError = (error: HTTPError): Response => {
const headers = new Headers(error.response.headers)
headers.delete('content-length')
let body: BodyInit | null = null
if (typeof error.data === 'string')
body = error.data
else if (error.data !== undefined)
body = JSON.stringify(error.data)
if (body !== null && !headers.has('content-type'))
headers.set('content-type', ContentType.json)
return new Response(body, {
status: error.response.status,
statusText: error.response.statusText,
headers,
})
}
const afterResponseErrorCode = (otherOptions: IOtherOptions): AfterResponseHook => {
return async ({ response }) => {
if (!/^([23])\d{2}$/.test(String(response.status))) {
@@ -209,7 +229,7 @@ async function base<T>(url: string, options: FetchOptionType = {}, otherOptions:
}
catch (error) {
if (error instanceof HTTPError)
throw error.response.clone()
throw createResponseFromHTTPError(error)
throw error
}