1- import { ALLOW_TEST_SUITE_WEBSITE , describeIf , TEST_PRODUCTION } from "../lib" ;
2- import { Identity , idmux , scrape , scrapeRaw , scrapeTimeout } from "./lib" ;
1+ import {
2+ ALLOW_TEST_SUITE_WEBSITE ,
3+ describeIf ,
4+ TEST_SUITE_WEBSITE ,
5+ } from "../lib" ;
6+ import { Identity , idmux , scrapeRaw , scrapeTimeout } from "./lib" ;
37
48let identity : Identity ;
59
@@ -13,11 +17,11 @@ beforeAll(async () => {
1317
1418describeIf ( ALLOW_TEST_SUITE_WEBSITE ) ( "V2 Scrape redactPII (schema)" , ( ) => {
1519 it . concurrent (
16- "accepts redactPII: true when `pii` is not in formats " ,
20+ "accepts redactPII: true with markdown output " ,
1721 async ( ) => {
1822 const res = await scrapeRaw (
1923 {
20- url : "https://firecrawl.dev" ,
24+ url : TEST_SUITE_WEBSITE ,
2125 formats : [ "markdown" ] ,
2226 redactPII : true ,
2327 } ,
@@ -36,8 +40,8 @@ describeIf(ALLOW_TEST_SUITE_WEBSITE)("V2 Scrape redactPII (schema)", () => {
3640 async ( ) => {
3741 const res = await scrapeRaw (
3842 {
39- url : "https://firecrawl.dev" ,
40- formats : [ "markdown" , "pii" ] ,
43+ url : TEST_SUITE_WEBSITE ,
44+ formats : [ "markdown" ] ,
4145 // typed as boolean, but we want to confirm the API rejects strings.
4246 // eslint-disable-next-line @typescript-eslint/no-explicit-any
4347 redactPII : "yes" as any ,
@@ -56,8 +60,8 @@ describeIf(ALLOW_TEST_SUITE_WEBSITE)("V2 Scrape redactPII (schema)", () => {
5660 async ( ) => {
5761 const res = await scrapeRaw (
5862 {
59- url : "https://firecrawl.dev" ,
60- formats : [ "markdown" , "pii" ] ,
63+ url : TEST_SUITE_WEBSITE ,
64+ formats : [ "markdown" ] ,
6165 // eslint-disable-next-line @typescript-eslint/no-explicit-any
6266 redactPII : {
6367 mode : "accurate" ,
@@ -68,12 +72,9 @@ describeIf(ALLOW_TEST_SUITE_WEBSITE)("V2 Scrape redactPII (schema)", () => {
6872 identity ,
6973 ) ;
7074
71- // The page may not have PII (so spans can be empty), but the
72- // request itself must validate and the response must include
73- // the `pii` block.
7475 expect ( res . statusCode ) . toBe ( 200 ) ;
7576 expect ( res . body . success ) . toBe ( true ) ;
76- expect ( res . body . data . pii ) . toBeDefined ( ) ;
77+ expect ( res . body . data . pii ) . toBeUndefined ( ) ;
7778 } ,
7879 scrapeTimeout ,
7980 ) ;
@@ -83,8 +84,8 @@ describeIf(ALLOW_TEST_SUITE_WEBSITE)("V2 Scrape redactPII (schema)", () => {
8384 async ( ) => {
8485 const res = await scrapeRaw (
8586 {
86- url : "https://firecrawl.dev" ,
87- formats : [ "markdown" , "pii" ] ,
87+ url : TEST_SUITE_WEBSITE ,
88+ formats : [ "markdown" ] ,
8889 // "model" is the fire-privacy internal mode, not the
8990 // public surface — must be rejected.
9091 // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -99,106 +100,3 @@ describeIf(ALLOW_TEST_SUITE_WEBSITE)("V2 Scrape redactPII (schema)", () => {
99100 scrapeTimeout ,
100101 ) ;
101102} ) ;
102-
103- describeIf ( TEST_PRODUCTION ) ( "V2 Scrape redactPII (e2e)" , ( ) => {
104- it (
105- "returns pii block with spans and replaces document.markdown with redacted content" ,
106- async ( ) => {
107- // A page with named entities and an email so heuristic recognizers fire
108- // even when fire-privacy is in heuristics-only mode.
109- const data = await scrape (
110- {
111- url : "https://en.wikipedia.org/wiki/Alan_Turing" ,
112- formats : [ "markdown" , "pii" ] ,
113- redactPII : true ,
114- } ,
115- identity ,
116- ) ;
117-
118- // Scrape always succeeds regardless of fire-privacy outcome.
119- expect ( data . pii ) . toBeDefined ( ) ;
120- expect ( [ "ok" , "skipped" , "failed" ] ) . toContain ( data . pii ! . status ) ;
121-
122- if ( data . pii ! . status === "ok" ) {
123- expect ( typeof data . pii ! . redactedMarkdown ) . toBe ( "string" ) ;
124- // document.markdown is the redacted version, not the raw one.
125- expect ( data . markdown ) . toBe ( data . pii ! . redactedMarkdown ) ;
126-
127- expect ( data . pii ! . spans . length ) . toBeGreaterThan ( 0 ) ;
128- expect ( data . pii ! . spans [ 0 ] ) . toEqual (
129- expect . objectContaining ( {
130- start : expect . any ( Number ) ,
131- end : expect . any ( Number ) ,
132- kind : expect . any ( String ) ,
133- } ) ,
134- ) ;
135- // counts should sum to the number of spans with a mapped entity.
136- const mappedSpanCount = data . pii ! . spans . filter ( s => s . entity ) . length ;
137- const totalCount = Object . values ( data . pii ! . counts ?? { } ) . reduce (
138- ( a , b ) => a + ( b ?? 0 ) ,
139- 0 ,
140- ) ;
141- expect ( totalCount ) . toBe ( mappedSpanCount ) ;
142- } else if ( data . pii ! . status === "failed" ) {
143- expect ( data . pii ! . redactedMarkdown ) . toBeNull ( ) ;
144- expect ( data . pii ! . reason ) . toBeDefined ( ) ;
145- // Fail closed: no raw markdown leaks through when redaction failed.
146- expect ( data . markdown ) . toBeUndefined ( ) ;
147- }
148- } ,
149- scrapeTimeout ,
150- ) ;
151-
152- it (
153- "fails closed when fire-privacy is unreachable — pii.status is failed, markdown is empty" ,
154- async ( ) => {
155- const data = await scrape (
156- {
157- url : "https://firecrawl.dev" ,
158- formats : [ "markdown" , "pii" ] ,
159- redactPII : true ,
160- } ,
161- identity ,
162- ) ;
163-
164- expect ( data . pii ) . toBeDefined ( ) ;
165- // We don't pin to a specific outcome — could be ok if fire-privacy
166- // is reachable in this environment, or one of skipped/failed otherwise.
167- // The contract is: scrape still succeeds (no error response).
168- expect ( [ "ok" , "skipped" , "failed" ] ) . toContain ( data . pii ! . status ) ;
169-
170- if ( data . pii ! . status === "ok" ) {
171- expect ( data . markdown ) . toBe ( data . pii ! . redactedMarkdown ) ;
172- } else {
173- expect ( data . pii ! . reason ) . toBeDefined ( ) ;
174- // Markdown is empty on failed / skipped-with-null-redacted; on
175- // upstream_skipped / empty_input it passes through (equal to
176- // redactedMarkdown). Verify the invariant: markdown matches
177- // redactedMarkdown (or is fail-closed empty).
178- if ( data . pii ! . redactedMarkdown === null ) {
179- expect ( data . markdown ) . toBe ( "" ) ;
180- } else {
181- expect ( data . markdown ) . toBe ( data . pii ! . redactedMarkdown ) ;
182- }
183- }
184- } ,
185- scrapeTimeout ,
186- ) ;
187-
188- it (
189- "omits pii block when redactPII is false even if `pii` is in formats" ,
190- async ( ) => {
191- const data = await scrape (
192- {
193- url : "https://firecrawl.dev" ,
194- formats : [ "markdown" , "pii" ] ,
195- } ,
196- identity ,
197- ) ;
198-
199- expect ( typeof data . markdown ) . toBe ( "string" ) ;
200- expect ( data . pii ) . toBeUndefined ( ) ;
201- } ,
202- scrapeTimeout ,
203- ) ;
204- } ) ;
0 commit comments