f920ca8920
- Added models for support messages, SLA policies, tickets, ticket events, and ticket links. - Created routes for help, help admin, newsletter, recommendations, and support for both customer and admin. - Developed services for help, marketing (newsletter), and recommendations. - Introduced support service for ticket management, including creation, replies, transitions, and attachments. - Added validation schemas for support recommendations and ticket management. - Implemented a cron job for support reconciliation and recommendation cleanup. - Created migration for new support and recommendation database tables. - Added unit tests for validation and policy checks related to Phase 10 features.
21 lines
2.9 KiB
JavaScript
21 lines
2.9 KiB
JavaScript
jest.mock("../../app/services/activity.service",()=>({logActivity:jest.fn()}));
|
|
const schemas=require("../../app/validation/supportRecommendation.schemas"),newsletter=require("../../app/services/marketing/newsletter.service"),help=require("../../app/services/help/help.service"),support=require("../../app/services/support/support.service"),permissions=require("../../app/constants/permissions");
|
|
const parse=(schema,body)=>schema.safeParse({body,params:{},query:{}});
|
|
describe("Phase 10 validation and policy",()=>{
|
|
test("ticket accepts safe customer fields",()=>expect(parse(schemas.ticketCreate,{subject:"Missing parcel",message:"Please check this order",attachmentIds:[],source:"WEB"}).success).toBe(true));
|
|
test("ticket rejects ownership injection",()=>expect(parse(schemas.ticketCreate,{subject:"Missing parcel",message:"Please check",customerUserId:"other"}).success).toBe(false));
|
|
test("customer cannot submit priority",()=>expect(parse(schemas.ticketCreate,{subject:"Urgent parcel",message:"Please check",priority:"URGENT"}).success).toBe(false));
|
|
test("empty support messages are rejected",()=>expect(parse(schemas.message,{message:" "}).success).toBe(false));
|
|
test("support attachments are bounded",()=>expect(parse(schemas.message,{message:"ok",attachmentIds:[1,2,3,4,5,6]}).success).toBe(false));
|
|
test("ticket links use a strict resource allowlist",()=>expect(parse(schemas.link,{type:"USER",id:"x"}).success).toBe(false));
|
|
test("closed tickets have no outbound transitions",()=>expect(support.transitions.CLOSED).toEqual([]));
|
|
test("resolved tickets may explicitly reopen",()=>expect(support.transitions.RESOLVED).toContain("WAITING_FOR_SUPPORT"));
|
|
test("newsletter email normalization is deterministic",()=>expect(newsletter.normalize(" PERSON@Example.COM ")).toBe("person@example.com"));
|
|
test("newsletter authorization tokens are hashable without storage of raw token",()=>{const token="a-secure-random-token";expect(newsletter.hash(token)).toMatch(/^[a-f0-9]{64}$/);expect(newsletter.hash(token)).not.toBe(token);});
|
|
test("newsletter source is allowlisted",()=>expect(parse(schemas.newsletter,{email:"a@example.com",source:"SCRAPED_LIST"}).success).toBe(false));
|
|
test("client event schema only accepts product views",()=>expect(parse(schemas.viewEvent,{eventId:"evt-1",productId:"p1",eventType:"PURCHASE"}).success).toBe(false));
|
|
test("client event rejects unknown mutation fields",()=>expect(parse(schemas.viewEvent,{eventId:"evt-1",productId:"p1",source:"WEB",email:"private@example.com"}).success).toBe(false));
|
|
test("help content strips HTML tags",()=>expect(help.clean("<script>alert(1)</script>Safe")).toBe("alert(1)Safe"));
|
|
test("all privileged Phase 10 permissions are explicit",()=>expect([permissions.SUPPORT_TICKETS_READ,permissions.HELP_MANAGE,permissions.NEWSLETTER_SUBSCRIBERS_READ,permissions.RECOMMENDATIONS_MANAGE]).toEqual(["support.tickets.read","help.manage","newsletter.subscribers.read","recommendations.manage"]));
|
|
});
|