Skip to content

Commit 3da4848

Browse files
committed
test cases for static url flow
1 parent 6a590b6 commit 3da4848

File tree

4 files changed

+682
-0
lines changed

4 files changed

+682
-0
lines changed
Lines changed: 368 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,368 @@
1+
import * as _ from "../../../../support/Objects/ObjectsCore";
2+
import PageList from "../../../../support/Pages/PageList";
3+
import EditorNavigation, {
4+
EntityType,
5+
} from "../../../../support/Pages/EditorNavigation";
6+
7+
describe(
8+
"Static URL - Page Slug Persistence",
9+
{ tags: ["@tag.Settings"] },
10+
() => {
11+
let applicationSlug: string;
12+
let page1Slug: string;
13+
let page2Slug: string;
14+
let page2Name: string;
15+
let oldPage1Route: string;
16+
let oldPage2Route: string;
17+
18+
before(() => {
19+
// Navigate to General Settings
20+
_.appSettings.OpenAppSettings();
21+
_.appSettings.GoToGeneralSettings();
22+
23+
// Before enabling static URL, get the existing routes for Page1 and Page2
24+
// Navigate to Page1 settings to get the old route
25+
_.appSettings.GoToPageSettings("Page1");
26+
27+
// Get the URL preview text which shows the old route format
28+
// The URL preview contains the full URL in a div with class "select-text"
29+
cy.get(".select-text")
30+
.should("be.visible")
31+
.then(($el) => {
32+
const fullUrl = $el.text().trim();
33+
// Extract the path part from the full URL
34+
// Format: https://domain.com/app/{app-slug}/{page-slug}-{pageId}
35+
const completePathMatch = fullUrl.match(/\/app\/[^\s]+/);
36+
if (completePathMatch) {
37+
oldPage1Route = completePathMatch[0].replace(/\/edit$/, ""); // Remove /edit if present
38+
}
39+
});
40+
41+
// Create Page2 before enabling static URL to get its old route
42+
PageList.AddNewPage("New blank page").then((newPageName) => {
43+
page2Name = newPageName;
44+
45+
// Navigate to Page2 settings to get the old route
46+
_.appSettings.OpenAppSettings();
47+
_.appSettings.GoToPageSettings(newPageName);
48+
49+
// Get the URL preview text for Page2 (old route format before static URL)
50+
cy.get(".select-text")
51+
.should("be.visible")
52+
.then(($el) => {
53+
const fullUrl = $el.text().trim();
54+
const completePathMatch = fullUrl.match(/\/app\/[^\s]+/);
55+
if (completePathMatch) {
56+
oldPage2Route = completePathMatch[0].replace(/\/edit$/, ""); // Remove /edit if present
57+
}
58+
});
59+
});
60+
61+
// Navigate back to General Settings
62+
_.appSettings.OpenAppSettings();
63+
_.appSettings.GoToGeneralSettings();
64+
65+
// Enable Static URL toggle
66+
cy.get("#t--general-settings-static-url").click();
67+
68+
// Wait for the API call to complete and get the auto-generated application slug
69+
cy.wait("@fetchAppSlugSuggestion").then((interception: any) => {
70+
expect(interception.response.statusCode).to.eq(200);
71+
applicationSlug = interception.response.body.data;
72+
73+
// Verify the slug input field is visible and contains the suggested slug
74+
cy.get("#t--general-settings-app-url")
75+
.should("be.visible")
76+
.should("have.value", applicationSlug);
77+
78+
// Click on "Apply" button to open confirmation modal
79+
cy.get('[data-testid="t--static-url-confirmation-confirm"]')
80+
.contains("Apply")
81+
.should("not.be.disabled")
82+
.click();
83+
84+
// Verify the modal appears with title "Change App Slug"
85+
cy.get('[data-testid="t--static-url-confirmation-modal"]').should(
86+
"be.visible",
87+
);
88+
cy.contains("Change App Slug").should("be.visible");
89+
90+
// Click on "Change App Slug" button in the modal to confirm
91+
cy.get('[data-testid="t--static-url-confirmation-modal"]').within(
92+
() => {
93+
cy.get('[data-testid="t--static-url-confirmation-confirm"]')
94+
.contains("Change App Slug")
95+
.should("be.visible")
96+
.click();
97+
},
98+
);
99+
100+
_.agHelper.ValidateToastMessage("App slug updated");
101+
102+
// Navigate to Page Settings of the first page
103+
_.appSettings.GoToPageSettings("Page1");
104+
});
105+
});
106+
107+
it("1. Should auto-generate page slug from page name and show in URL preview", () => {
108+
// Get the current page name
109+
cy.get("#t--page-settings-name")
110+
.invoke("val")
111+
.then((pageName) => {
112+
const pageNameStr = pageName as string;
113+
// Convert page name to expected slug format (lowercase, spaces replaced with hyphens)
114+
const expectedPageSlug = pageNameStr
115+
.toLowerCase()
116+
.trim()
117+
.replace(/\s+/g, "-")
118+
.replace(/[^a-z0-9-]/g, ""); // Remove any special characters except hyphens
119+
120+
// Get the current page slug from the input field
121+
cy.get("#t--page-settings-static-page-slug")
122+
.invoke("val")
123+
.then((pageSlug) => {
124+
const pageSlugStr = pageSlug as string;
125+
126+
// Verify the page slug starts with the expected slug derived from the page name
127+
// Backend may append a random hash after a hyphen for uniqueness
128+
expect(pageSlugStr).to.satisfy((slug: string) =>
129+
slug.startsWith(`${expectedPageSlug}`),
130+
);
131+
132+
// Verify the URL preview contains both the application slug and page slug
133+
cy.contains(`/app/${applicationSlug}/${pageSlugStr}`).should(
134+
"be.visible",
135+
);
136+
});
137+
});
138+
});
139+
140+
it("2. Should automatically persist page slug when available and reflect on page reload", () => {
141+
// Get the current page slug
142+
cy.get("#t--page-settings-static-page-slug")
143+
.invoke("val")
144+
.then((currentPageSlug) => {
145+
const currentPageSlugStr = currentPageSlug as string;
146+
147+
// Modify the page slug by appending "1"
148+
const modifiedPageSlug = currentPageSlugStr + "1";
149+
cy.get("#t--page-settings-static-page-slug")
150+
.clear()
151+
.type(modifiedPageSlug);
152+
153+
// Verify the "Available" message appears
154+
cy.contains("Available").should("be.visible");
155+
156+
// Verify the URL preview shows the modified page slug
157+
cy.contains(`/app/${applicationSlug}/${modifiedPageSlug}`).should(
158+
"be.visible",
159+
);
160+
161+
// Blur the input field to trigger auto-persistence (no confirmation modal)
162+
cy.get("#t--page-settings-static-page-slug").blur();
163+
164+
// Verify "Deploy app to apply this slug" message appears
165+
cy.contains("Deploy app to apply this slug").should("be.visible");
166+
167+
// Reload the page
168+
cy.reload();
169+
170+
// Wait for the page to load and navigate back to page settings
171+
_.appSettings.OpenAppSettings();
172+
_.appSettings.GoToPageSettings("Page1");
173+
174+
// Verify the page slug persists after reload
175+
cy.get("#t--page-settings-static-page-slug")
176+
.should("be.visible")
177+
.should("have.value", modifiedPageSlug);
178+
179+
// Store page1 slug for later use
180+
page1Slug = modifiedPageSlug;
181+
});
182+
});
183+
184+
it("3. Should show unavailable status for duplicate page slug and auto-persist when unique", () => {
185+
// Get the persisted page slug from test 2
186+
cy.get("#t--page-settings-static-page-slug")
187+
.invoke("val")
188+
.then((persistedPageSlug) => {
189+
const persistedPageSlugStr = persistedPageSlug as string;
190+
191+
// Navigate to Page2 settings (Page2 was created in before hook)
192+
_.appSettings.OpenAppSettings();
193+
_.appSettings.GoToPageSettings(page2Name);
194+
195+
// Try to use the same page slug from the previous page
196+
cy.get("#t--page-settings-static-page-slug")
197+
.clear()
198+
.type(persistedPageSlugStr);
199+
200+
// Verify the "Unavailable" message appears
201+
cy.contains("There is already a page with this slug.").should(
202+
"be.visible",
203+
);
204+
205+
// Change to another unique value
206+
const uniquePageSlug = persistedPageSlugStr + "2";
207+
cy.get("#t--page-settings-static-page-slug")
208+
.clear()
209+
.type(uniquePageSlug);
210+
211+
// Verify the "Available" message appears
212+
cy.contains("Available").should("be.visible");
213+
214+
// Blur the input field to trigger auto-persistence
215+
cy.get("#t--page-settings-static-page-slug").blur();
216+
217+
// Verify "Deploy app to apply this slug" message appears
218+
cy.contains("Deploy app to apply this slug").should("be.visible");
219+
220+
// Reload the page
221+
cy.reload();
222+
223+
// Wait for the page to load and navigate back to Page2 settings
224+
_.appSettings.OpenAppSettings();
225+
_.appSettings.GoToPageSettings(page2Name);
226+
227+
// Verify the page slug persists after reload
228+
cy.get("#t--page-settings-static-page-slug")
229+
.should("be.visible")
230+
.should("have.value", uniquePageSlug);
231+
232+
// Store page2 slug for later use
233+
page2Slug = uniquePageSlug;
234+
});
235+
});
236+
237+
it("4. Should validate routes are accessible in deployed application with static URLs", () => {
238+
// Navigate to Page1
239+
EditorNavigation.SelectEntityByName("Page1", EntityType.Page);
240+
241+
// Add Text widget to Page1
242+
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 300, 300);
243+
244+
// Select the Text widget and update its text
245+
EditorNavigation.SelectEntityByName("Text1", EntityType.Widget);
246+
_.propPane.UpdatePropertyFieldValue("Text", "This is page1");
247+
248+
// Navigate to Page2 (stored from test 3)
249+
EditorNavigation.SelectEntityByName(page2Name, EntityType.Page);
250+
251+
// Add Text widget to Page2
252+
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 300, 300);
253+
254+
// Select the Text widget and update its text
255+
EditorNavigation.SelectEntityByName("Text1", EntityType.Widget);
256+
_.propPane.UpdatePropertyFieldValue("Text", "This is page2");
257+
258+
// Deploy the application
259+
_.deployMode.DeployApp();
260+
261+
// First, navigate to Page1 after deployment
262+
cy.visit(`/app/${applicationSlug}/${page1Slug}`, { timeout: 10000 });
263+
264+
// Validate the URL contains the static URL route for Page1
265+
cy.url().should("include", `/app/${applicationSlug}/${page1Slug}`);
266+
267+
// Assert the text "This is page1" is visible on Page1
268+
cy.contains("This is page1").should("be.visible");
269+
270+
// Navigate to Page2
271+
cy.visit(`/app/${applicationSlug}/${page2Slug}`, { timeout: 10000 });
272+
273+
// Validate the URL contains the static URL route for Page2
274+
cy.url().should("include", `/app/${applicationSlug}/${page2Slug}`);
275+
276+
// Assert the text "This is page2" is visible on Page2
277+
cy.contains("This is page2").should("be.visible");
278+
279+
// Navigate back to Page1
280+
cy.visit(`/app/${applicationSlug}/${page1Slug}`, { timeout: 10000 });
281+
282+
// Validate the URL contains the static URL route for Page1
283+
cy.url().should("include", `/app/${applicationSlug}/${page1Slug}`);
284+
285+
// Assert the text "This is page1" is visible on Page1
286+
cy.contains("This is page1").should("be.visible");
287+
});
288+
289+
it("5. Should validate old routes still work and redirect to respective pages", () => {
290+
// Navigate to Page1 using the old route
291+
cy.visit(oldPage1Route, { timeout: 10000 });
292+
293+
// Verify that Page1 opens correctly (should redirect or show Page1 content)
294+
// The old route should still work and show the page
295+
cy.contains("This is page1").should("be.visible");
296+
297+
// Navigate to Page2 using the old route
298+
cy.visit(oldPage2Route, { timeout: 10000 });
299+
300+
// Verify that Page2 opens correctly (should redirect or show Page2 content)
301+
// The old route should still work and show the page
302+
cy.contains("This is page2").should("be.visible");
303+
});
304+
305+
it("6. Should validate only old routes work after disabling static URL", () => {
306+
// Navigate back to editor from deployed mode
307+
_.deployMode.NavigateBacktoEditor();
308+
309+
// Navigate to General Settings
310+
_.appSettings.OpenAppSettings();
311+
_.appSettings.GoToGeneralSettings();
312+
313+
// Disable Static URL toggle
314+
cy.get("#t--general-settings-static-url").click();
315+
316+
// Verify the confirmation modal appears for disabling
317+
cy.get('[data-testid="t--static-url-confirmation-modal"]').should(
318+
"be.visible",
319+
);
320+
cy.contains("Disable App Static URL").should("be.visible");
321+
322+
// Click on "Disable Static URL" button in the modal to confirm
323+
cy.get('[data-testid="t--static-url-confirmation-modal"]').within(() => {
324+
cy.get('[data-testid="t--static-url-confirmation-confirm"]')
325+
.contains("Disable Static URL")
326+
.should("be.visible")
327+
.click();
328+
});
329+
330+
// Wait for the snackbar notification
331+
_.agHelper.ValidateToastMessage(
332+
"Static URL disabled. The app has reverted to default Appsmith URLs.",
333+
);
334+
335+
// Verify the slug input field is no longer visible (toggle is off)
336+
cy.get("#t--general-settings-app-url").should("not.exist");
337+
338+
// Deploy the application
339+
_.deployMode.DeployApp();
340+
341+
// Verify that old routes still work
342+
// Navigate to Page1 using the old route
343+
cy.visit(oldPage1Route, { timeout: 10000 });
344+
cy.contains("This is page1").should("be.visible");
345+
346+
// Navigate to Page2 using the old route
347+
cy.visit(oldPage2Route, { timeout: 10000 });
348+
cy.contains("This is page2").should("be.visible");
349+
350+
// Verify that static URL routes do NOT work
351+
// Try to navigate to Page1 using static URL route - should fail or redirect
352+
cy.visit(`/app/${applicationSlug}/${page1Slug}`, {
353+
timeout: 10000,
354+
failOnStatusCode: false,
355+
});
356+
// The static URL route should not work - page should not show the expected content
357+
cy.contains("This is page1").should("not.exist");
358+
359+
// Try to navigate to Page2 using static URL route - should fail or redirect
360+
cy.visit(`/app/${applicationSlug}/${page2Slug}`, {
361+
timeout: 10000,
362+
failOnStatusCode: false,
363+
});
364+
// The static URL route should not work - page should not show the expected content
365+
cy.contains("This is page2").should("not.exist");
366+
});
367+
},
368+
);

0 commit comments

Comments
 (0)