1- import { render , screen , waitFor } from "@testing-library/react" ;
1+ import { render , screen } from "@testing-library/react" ;
22import { MockedProvider } from "@apollo/client/testing" ;
3- import { GraphQLError } from "graphql" ;
43import { describe , it , expect , beforeEach , vi , afterEach } from "vitest" ;
54import { MemoryRouter , Route , Routes } from "react-router-dom" ;
65import { ExtractDetailRoute } from "../ExtractDetailRoute" ;
7- import { openedExtract } from "../../../graphql/cache" ;
8- import { RESOLVE_EXTRACT_BY_ID } from "../../../graphql/queries" ;
6+ import {
7+ openedExtract ,
8+ routeLoading ,
9+ routeError ,
10+ } from "../../../graphql/cache" ;
911import type { ExtractType } from "../../../types/graphql-api" ;
1012
1113vi . mock ( "../../../views/ExtractDetail" , ( ) => ( {
@@ -31,13 +33,11 @@ vi.mock("../../widgets/ModernErrorDisplay", () => ({
3133} ) ) ;
3234
3335/**
34- * Tests for ExtractDetailRoute.
36+ * Tests for ExtractDetailRoute (dumb consumer) .
3537 *
36- * ExtractDetailRoute resolves /extracts/:extractId by either reusing the
37- * openedExtract reactive var (when it matches the URL id) or executing a
38- * RESOLVE_EXTRACT_BY_ID query. It surfaces loading, error, and not-found
39- * states with the ModernLoading/Error displays and defers to ExtractDetail
40- * on success.
38+ * URL parsing and the RESOLVE_EXTRACT_BY_ID query now live in
39+ * CentralRouteManager. ExtractDetailRoute reads openedExtract / routeLoading
40+ * / routeError and renders one of three states.
4141 */
4242describe ( "ExtractDetailRoute" , ( ) => {
4343 const mockExtract : ExtractType = {
@@ -50,115 +50,61 @@ describe("ExtractDetailRoute", () => {
5050 myPermissions : [ "read_extract" ] ,
5151 } as unknown as ExtractType ;
5252
53- const renderRoute = ( extractId : string | undefined , mocks : any [ ] = [ ] ) => {
54- const path = extractId ? `/extracts/${ extractId } ` : "/extracts/" ;
55- return render (
56- < MockedProvider mocks = { mocks } addTypename = { false } >
57- < MemoryRouter initialEntries = { [ path ] } >
53+ const renderRoute = ( ) =>
54+ render (
55+ < MockedProvider mocks = { [ ] } addTypename = { false } >
56+ < MemoryRouter initialEntries = { [ "/extracts/extract-123" ] } >
5857 < Routes >
5958 < Route
6059 path = "/extracts/:extractId"
6160 element = { < ExtractDetailRoute /> }
6261 />
63- < Route path = "/extracts/" element = { < ExtractDetailRoute /> } />
6462 </ Routes >
6563 </ MemoryRouter >
6664 </ MockedProvider >
6765 ) ;
68- } ;
6966
7067 beforeEach ( ( ) => {
7168 openedExtract ( null ) ;
69+ routeLoading ( false ) ;
70+ routeError ( null ) ;
7271 } ) ;
7372
7473 afterEach ( ( ) => {
7574 vi . clearAllMocks ( ) ;
7675 openedExtract ( null ) ;
76+ routeLoading ( false ) ;
77+ routeError ( null ) ;
7778 } ) ;
7879
79- it ( "shows 'No extract ID provided' when extractId param is missing" , ( ) => {
80- renderRoute ( undefined ) ;
81- expect (
82- screen . getByText ( / E r r o r : .* N o e x t r a c t I D p r o v i d e d / )
83- ) . toBeInTheDocument ( ) ;
84- } ) ;
85-
86- it ( "skips the query and renders ExtractDetail when reactive var already has a matching extract" , ( ) => {
87- openedExtract ( { ...mockExtract , id : "extract-123" } as any ) ;
88-
89- renderRoute ( "extract-123" ) ;
90-
91- // Query is skipped because existingExtract.id === extractId, so we
92- // should see the ExtractDetail view immediately.
93- expect ( screen . getByText ( "ExtractDetail Component" ) ) . toBeInTheDocument ( ) ;
94- } ) ;
95-
96- it ( "renders loading state while resolving an unfamiliar extract id" , async ( ) => {
97- renderRoute ( "extract-999" , [
98- {
99- request : {
100- query : RESOLVE_EXTRACT_BY_ID ,
101- variables : { extractId : "extract-999" } ,
102- } ,
103- delay : 100 ,
104- result : { data : { extract : { ...mockExtract , id : "extract-999" } } } ,
105- } ,
106- ] ) ;
107-
80+ it ( "shows loading display when routeLoading is true and no extract is resolved" , ( ) => {
81+ routeLoading ( true ) ;
82+ renderRoute ( ) ;
10883 expect ( screen . getByText ( "Loading..." ) ) . toBeInTheDocument ( ) ;
10984 } ) ;
11085
111- it ( "renders error state when RESOLVE_EXTRACT_BY_ID returns an error" , async ( ) => {
112- renderRoute ( "extract-404" , [
113- {
114- request : {
115- query : RESOLVE_EXTRACT_BY_ID ,
116- variables : { extractId : "extract-404" } ,
117- } ,
118- result : { errors : [ new GraphQLError ( "Extract not found" ) ] } ,
119- } ,
120- ] ) ;
121-
122- await waitFor ( ( ) => {
123- expect ( screen . getByText ( / E r r o r : / ) ) . toBeInTheDocument ( ) ;
124- } ) ;
86+ it ( "shows error display when routeError is set" , ( ) => {
87+ routeError ( new Error ( "Boom" ) ) ;
88+ renderRoute ( ) ;
89+ expect ( screen . getByText ( / E r r o r : .* B o o m / ) ) . toBeInTheDocument ( ) ;
12590 } ) ;
12691
127- it ( "renders not-found state when the query resolves with no extract" , async ( ) => {
128- renderRoute ( "extract-missing" , [
129- {
130- request : {
131- query : RESOLVE_EXTRACT_BY_ID ,
132- variables : { extractId : "extract-missing" } ,
133- } ,
134- result : { data : { extract : null } } ,
135- } ,
136- ] ) ;
137-
138- await waitFor ( ( ) => {
139- expect ( screen . getByText ( / E r r o r : .* E x t r a c t n o t f o u n d / ) ) . toBeInTheDocument ( ) ;
140- } ) ;
92+ it ( "shows 'Extract not found' when no extract is resolved and no error/loading is set" , ( ) => {
93+ renderRoute ( ) ;
94+ expect ( screen . getByText ( / E r r o r : .* E x t r a c t n o t f o u n d / ) ) . toBeInTheDocument ( ) ;
14195 } ) ;
14296
143- it ( "renders ExtractDetail and sets openedExtract when the query resolves successfully" , async ( ) => {
144- const resolved = {
145- ...mockExtract ,
146- id : "extract-555" ,
147- name : "Resolved Extract" ,
148- } ;
149- renderRoute ( "extract-555" , [
150- {
151- request : {
152- query : RESOLVE_EXTRACT_BY_ID ,
153- variables : { extractId : "extract-555" } ,
154- } ,
155- result : { data : { extract : resolved } } ,
156- } ,
157- ] ) ;
97+ it ( "renders ExtractDetail when an extract has been resolved" , ( ) => {
98+ openedExtract ( mockExtract as any ) ;
99+ renderRoute ( ) ;
100+ expect ( screen . getByText ( "ExtractDetail Component" ) ) . toBeInTheDocument ( ) ;
101+ } ) ;
158102
159- await waitFor ( ( ) => {
160- expect ( screen . getByText ( "ExtractDetail Component" ) ) . toBeInTheDocument ( ) ;
161- } ) ;
162- expect ( openedExtract ( ) ?. id ) . toBe ( "extract-555" ) ;
103+ it ( "prefers a resolved extract over the loading state when both are set" , ( ) => {
104+ routeLoading ( true ) ;
105+ openedExtract ( mockExtract as any ) ;
106+ renderRoute ( ) ;
107+ expect ( screen . getByText ( "ExtractDetail Component" ) ) . toBeInTheDocument ( ) ;
108+ expect ( screen . queryByText ( "Loading..." ) ) . toBeNull ( ) ;
163109 } ) ;
164110} ) ;
0 commit comments