@@ -15,6 +15,19 @@ const RESIDENTIAL_LISTING_EDIT_PATH =
1515const ALTERNATE_BUSINESS_DESCRIPTION =
1616 "A demo business listing with a slightly different description for e2e coverage." ;
1717
18+ function requireHref ( href : string | null ) {
19+ expect (
20+ href ,
21+ "Expected listing photo thumbnail to have an href"
22+ ) . not . toBeNull ( ) ;
23+
24+ if ( ! href ) {
25+ throw new Error ( "Expected listing photo thumbnail to have an href" ) ;
26+ }
27+
28+ return href ;
29+ }
30+
1831test ( "profile loads the seeded host account and listings" , async ( { page } ) => {
1932 await signIn ( page , { email : HOST_EMAIL , redirectTo : "/profile" } ) ;
2033
@@ -83,7 +96,7 @@ test("listing edit saves and restores seeded business fields", async ({
8396 const listingWriteForm = page . getByTestId ( "listing-write-form" ) ;
8497 await expect ( listingWriteForm ) . toBeVisible ( ) ;
8598 const descriptionInput = listingWriteForm . locator ( "#description" ) . first ( ) ;
86- const visibilityInput = listingWriteForm . locator ( "#visibility" ) ;
99+ const visibilityInput = listingWriteForm . locator ( "#visibility" ) . first ( ) ;
87100 const originalDescription = await descriptionInput . inputValue ( ) ;
88101 const originalVisibility = await visibilityInput . inputValue ( ) ;
89102 const updatedDescription =
@@ -111,7 +124,7 @@ test("listing edit saves and restores seeded business fields", async ({
111124 await expect ( listingWriteForm . locator ( "#description" ) . first ( ) ) . toHaveValue (
112125 updatedDescription
113126 ) ;
114- await expect ( listingWriteForm . locator ( "#visibility" ) ) . toHaveValue (
127+ await expect ( listingWriteForm . locator ( "#visibility" ) . first ( ) ) . toHaveValue (
115128 updatedVisibility
116129 ) ;
117130
@@ -132,11 +145,87 @@ test("listing edit saves and restores seeded business fields", async ({
132145 await expect ( listingWriteForm . locator ( "#description" ) . first ( ) ) . toHaveValue (
133146 originalDescription
134147 ) ;
135- await expect ( listingWriteForm . locator ( "#visibility" ) ) . toHaveValue (
148+ await expect ( listingWriteForm . locator ( "#visibility" ) . first ( ) ) . toHaveValue (
136149 originalVisibility
137150 ) ;
138151} ) ;
139152
153+ test ( "dirty listing edit asks before viewing the saved listing" , async ( {
154+ page,
155+ } ) => {
156+ await signIn ( page , {
157+ email : HOST_EMAIL ,
158+ redirectTo : BUSINESS_LISTING_EDIT_PATH ,
159+ } ) ;
160+
161+ const listingWriteForm = page . getByTestId ( "listing-write-form" ) ;
162+ await expect ( listingWriteForm ) . toBeVisible ( ) ;
163+ const descriptionInput = listingWriteForm . locator ( "#description" ) . first ( ) ;
164+ const draftDescription = `Unsaved listing preview draft ${ Date . now ( ) } ` ;
165+ const viewListingButton = page . getByRole ( "button" , { name : "View listing" } ) ;
166+
167+ await descriptionInput . fill ( draftDescription ) ;
168+
169+ await viewListingButton . click ( ) ;
170+ await expect (
171+ page . getByRole ( "heading" , { name : "Discard changes" } )
172+ ) . toBeVisible ( ) ;
173+ await expect (
174+ page . getByText (
175+ "You have unsaved changes. Are you sure you want to discard them and leave?"
176+ )
177+ ) . toBeVisible ( ) ;
178+ await page . getByRole ( "button" , { name : "No, go back" } ) . click ( ) ;
179+
180+ await expect ( page ) . toHaveURL ( / \/ p r o f i l e \/ l i s t i n g s \/ d e m o - i n n e r - w e s t - c a f e $ / ) ;
181+ await expect ( descriptionInput ) . toHaveValue ( draftDescription ) ;
182+
183+ await viewListingButton . click ( ) ;
184+ await page . getByRole ( "button" , { name : "Yes, discard" } ) . click ( ) ;
185+
186+ await expect ( page ) . toHaveURL ( / \/ l i s t i n g s \/ d e m o - i n n e r - w e s t - c a f e $ / ) ;
187+ } ) ;
188+
189+ test ( "dirty new listing forms warn before closing or reloading the page" , async ( {
190+ page,
191+ } ) => {
192+ await signIn ( page , {
193+ email : HOST_EMAIL ,
194+ redirectTo : "/profile/listings/new/business" ,
195+ } ) ;
196+
197+ await expect ( page . getByTestId ( "listing-write-form" ) ) . toBeVisible ( ) ;
198+ await page . locator ( "#name" ) . fill ( `Unsaved new listing ${ Date . now ( ) } ` ) ;
199+
200+ const dialogPromise = page . waitForEvent ( "dialog" ) ;
201+ const reloadPromise = page . reload ( { waitUntil : "domcontentloaded" } ) ;
202+ const dialog = await dialogPromise ;
203+ expect ( dialog . type ( ) ) . toBe ( "beforeunload" ) ;
204+ await dialog . accept ( ) ;
205+ await reloadPromise ;
206+ } ) ;
207+
208+ test ( "clean listing edit views the saved listing without asking" , async ( {
209+ page,
210+ } ) => {
211+ await signIn ( page , {
212+ email : HOST_EMAIL ,
213+ redirectTo : BUSINESS_LISTING_EDIT_PATH ,
214+ } ) ;
215+
216+ await expect ( page . getByTestId ( "listing-write-form" ) ) . toBeVisible ( ) ;
217+ const dialogMessages : string [ ] = [ ] ;
218+ page . on ( "dialog" , async ( dialog ) => {
219+ dialogMessages . push ( dialog . message ( ) ) ;
220+ await dialog . dismiss ( ) ;
221+ } ) ;
222+
223+ await page . getByRole ( "link" , { name : "View listing" } ) . click ( ) ;
224+
225+ await expect ( page ) . toHaveURL ( / \/ l i s t i n g s \/ d e m o - i n n e r - w e s t - c a f e $ / ) ;
226+ expect ( dialogMessages ) . toEqual ( [ ] ) ;
227+ } ) ;
228+
140229test ( "residential listing edit leaves avatar management on the profile page" , async ( {
141230 page,
142231} ) => {
@@ -159,13 +248,13 @@ test("listing photos open in a dedicated photo tab", async ({ page }) => {
159248 await expect ( firstThumbnail ) . toBeVisible ( ) ;
160249 await expect ( firstThumbnail ) . toHaveAttribute ( "target" , "_blank" ) ;
161250
162- const href = await firstThumbnail . getAttribute ( "href" ) ;
251+ const href = requireHref ( await firstThumbnail . getAttribute ( "href" ) ) ;
163252 expect ( href ) . toBe (
164253 "/listings/demo-marrickville-compost/photos/demo/garden.jpg"
165254 ) ;
166255
167256 const photoPage = await page . context ( ) . newPage ( ) ;
168- await photoPage . goto ( `http://127.0.0.1:3000 ${ href } ` ) ;
257+ await photoPage . goto ( new URL ( href , page . url ( ) ) . toString ( ) ) ;
169258 await expect ( photoPage . getByTestId ( "listing-photo-tab-viewer" ) ) . toBeVisible ( ) ;
170259 await expect ( photoPage . getByRole ( "navigation" ) ) . toHaveCount ( 0 ) ;
171260 await expect ( page ) . toHaveURL ( PUBLIC_MULTI_PHOTO_LISTING_PATH ) ;
@@ -192,13 +281,13 @@ test("map listing photos open in a dedicated photo tab without disturbing the dr
192281 await expect ( firstThumbnail ) . toBeVisible ( ) ;
193282 await expect ( firstThumbnail ) . toHaveAttribute ( "target" , "_blank" ) ;
194283
195- const href = await firstThumbnail . getAttribute ( "href" ) ;
284+ const href = requireHref ( await firstThumbnail . getAttribute ( "href" ) ) ;
196285 expect ( href ) . toBe (
197286 "/listings/demo-marrickville-compost/photos/demo/garden.jpg"
198287 ) ;
199288
200289 const photoPage = await page . context ( ) . newPage ( ) ;
201- await photoPage . goto ( `http://127.0.0.1:3000 ${ href } ` ) ;
290+ await photoPage . goto ( new URL ( href , page . url ( ) ) . toString ( ) ) ;
202291 await expect ( photoPage . getByTestId ( "listing-photo-tab-viewer" ) ) . toBeVisible ( ) ;
203292 await expect ( page ) . toHaveURL ( MAP_MULTI_PHOTO_LISTING_PATH ) ;
204293 await expect ( firstThumbnail ) . toBeVisible ( ) ;
0 commit comments