299 lines
8.3 KiB
TypeScript
299 lines
8.3 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import { encode } from "next-auth/jwt";
|
|
|
|
const SESSION_COOKIE_NAME = "authjs.session-token";
|
|
|
|
async function createSessionCookie(type: "regular" | "admin" | "agent_admin" = "regular") {
|
|
const secret = process.env.AUTH_SECRET;
|
|
if (!secret) {
|
|
throw new Error("AUTH_SECRET 未配置,无法生成测试会话");
|
|
}
|
|
|
|
const token = await encode({
|
|
secret,
|
|
salt: SESSION_COOKIE_NAME,
|
|
token: {
|
|
sub: "product-planning-test-user",
|
|
id: "product-planning-test-user",
|
|
email: "product-planning-test@example.com",
|
|
name: "Product Planning Test User",
|
|
type,
|
|
},
|
|
});
|
|
|
|
return `${SESSION_COOKIE_NAME}=${token}`;
|
|
}
|
|
|
|
test.describe.serial("/api/product-planning unauthorized", () => {
|
|
test("guest cannot access reviews route", async ({ request }) => {
|
|
const response = await request.get("/api/product-planning/taobao/reviews?id=1234567890&page=1");
|
|
expect(response.status()).toBe(401);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
error: "未授权,请先登录",
|
|
});
|
|
});
|
|
|
|
test("guest cannot access template list route", async ({ request }) => {
|
|
const response = await request.get("/api/product-planning/templates");
|
|
expect(response.status()).toBe(401);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
error: "未授权,请先登录",
|
|
});
|
|
});
|
|
|
|
test("guest cannot access image analyze route", async ({ request }) => {
|
|
const response = await request.post("/api/product-planning/analyze-image", {
|
|
data: {
|
|
itemId: "123",
|
|
imageUrl: "https://example.com/demo.jpg",
|
|
},
|
|
});
|
|
expect(response.status()).toBe(401);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
error: "未授权,请先登录",
|
|
});
|
|
});
|
|
|
|
test("guest cannot access SKU analyze route", async ({ request }) => {
|
|
const response = await request.post("/api/product-planning/analyze-sku", {
|
|
data: {
|
|
itemId: "123",
|
|
platform: "taobao",
|
|
skus: [{ name: "原木款", price: 199 }],
|
|
},
|
|
});
|
|
expect(response.status()).toBe(401);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
error: "未授权,请先登录",
|
|
});
|
|
});
|
|
});
|
|
|
|
test.describe.serial("/api/product-planning", () => {
|
|
test("authenticated user gets 400 when reviews id is missing", async ({ request }) => {
|
|
const cookie = await createSessionCookie();
|
|
const response = await request.get("/api/product-planning/taobao/reviews?page=1", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
});
|
|
expect(response.status()).toBe(400);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "缺少商品ID参数",
|
|
});
|
|
});
|
|
|
|
test("authenticated user gets 400 when QA itemId is missing", async ({ request }) => {
|
|
const cookie = await createSessionCookie();
|
|
const response = await request.post("/api/product-planning/taobao/qa", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
data: {
|
|
itemId: "",
|
|
page: 1,
|
|
},
|
|
});
|
|
expect(response.status()).toBe(400);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "请求参数不合法",
|
|
});
|
|
});
|
|
|
|
test("authenticated user gets 400 when analyze rows are empty", async ({ request }) => {
|
|
const cookie = await createSessionCookie();
|
|
const response = await request.post("/api/product-planning/analyze", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
data: {
|
|
kind: "review",
|
|
rows: [],
|
|
},
|
|
});
|
|
expect(response.status()).toBe(400);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "请求参数不合法或 rows 为空",
|
|
});
|
|
});
|
|
|
|
test("authenticated user gets 400 when image analyze payload is invalid", async ({ request }) => {
|
|
const cookie = await createSessionCookie();
|
|
const response = await request.post("/api/product-planning/analyze-image", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
data: {
|
|
itemId: "",
|
|
imageUrl: "not-a-url",
|
|
},
|
|
});
|
|
expect(response.status()).toBe(400);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "请求参数不合法",
|
|
});
|
|
});
|
|
|
|
test("authenticated user gets 400 when SKU analyze payload is invalid", async ({ request }) => {
|
|
const cookie = await createSessionCookie();
|
|
const response = await request.post("/api/product-planning/analyze-sku", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
data: {
|
|
itemId: "",
|
|
platform: "taobao",
|
|
skus: [],
|
|
},
|
|
});
|
|
expect(response.status()).toBe(400);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "请求参数不合法或 skus 为空",
|
|
});
|
|
});
|
|
|
|
test("authenticated user gets 400 when item id is missing for competitor item route", async ({
|
|
request,
|
|
}) => {
|
|
const cookie = await createSessionCookie();
|
|
const response = await request.get("/api/product-planning/taobao/item", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
});
|
|
expect(response.status()).toBe(400);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "缺少商品ID参数",
|
|
});
|
|
});
|
|
|
|
test("authenticated user gets 400 when item id is missing for JD item route", async ({
|
|
request,
|
|
}) => {
|
|
const cookie = await createSessionCookie();
|
|
const response = await request.get("/api/product-planning/jd/item", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
});
|
|
expect(response.status()).toBe(400);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "缺少商品ID参数",
|
|
});
|
|
});
|
|
|
|
test("authenticated user gets 400 when item id is missing for month-sale route", async ({
|
|
request,
|
|
}) => {
|
|
const cookie = await createSessionCookie();
|
|
const response = await request.get("/api/product-planning/taobao/month-sale", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
});
|
|
expect(response.status()).toBe(400);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "缺少商品ID参数",
|
|
});
|
|
});
|
|
|
|
test("authenticated user gets 400 when keyword insight q is missing", async ({ request }) => {
|
|
const cookie = await createSessionCookie();
|
|
const response = await request.get("/api/product-planning/keyword-insight", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
});
|
|
expect(response.status()).toBe(400);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "缺少关键词参数",
|
|
});
|
|
});
|
|
|
|
test("regular user cannot upload shared templates", async ({ request }) => {
|
|
const cookie = await createSessionCookie("regular");
|
|
const response = await request.post("/api/product-planning/templates", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
});
|
|
expect(response.status()).toBe(403);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "需要管理员权限",
|
|
});
|
|
});
|
|
|
|
test("admin upload rejects missing template file", async ({ request }) => {
|
|
const cookie = await createSessionCookie("admin");
|
|
const response = await request.post("/api/product-planning/templates", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
multipart: {
|
|
categoryName: "换鞋凳",
|
|
},
|
|
});
|
|
expect(response.status()).toBe(400);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "缺少模板文件",
|
|
});
|
|
});
|
|
|
|
test("regular user cannot delete shared templates", async ({ request }) => {
|
|
const cookie = await createSessionCookie("regular");
|
|
const response = await request.delete("/api/product-planning/templates/mock-template-id", {
|
|
headers: {
|
|
Cookie: cookie,
|
|
},
|
|
});
|
|
expect(response.status()).toBe(403);
|
|
|
|
const payload = await response.json();
|
|
expect(payload).toMatchObject({
|
|
success: false,
|
|
error: "需要管理员权限",
|
|
});
|
|
});
|
|
});
|