Skip to content

Commit fba9ef2

Browse files
authored
feat(core): add org-level custom css support in sign-in-exp API (#7733)
1 parent eba2843 commit fba9ef2

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

packages/core/src/libraries/sign-in-experience/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,16 @@ export const createSignInExperienceLibrary = (
131131
return;
132132
}
133133
const organization = await trySafe(organizations.findById(organizationId));
134-
if (!organization?.branding) {
134+
const { branding, customCss } = organization ?? {};
135+
136+
if (!branding && !customCss) {
135137
return;
136138
}
137139

138-
return { branding: organization.branding };
140+
return {
141+
...(branding && { branding }),
142+
...(customCss && { customCss }),
143+
};
139144
};
140145

141146
const findApplicationSignInExperience = async (appId?: string) => {

packages/integration-tests/src/tests/experience/overrides.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ describe('overrides', () => {
3535
favicon: 'mock://fake-url-for-omni/favicon.ico',
3636
darkFavicon: 'mock://fake-url-for-omni/dark-favicon.ico',
3737
} satisfies Branding);
38+
const omniCustomCss = '.logto_main-content { background-color: #f00 !important; }';
3839

3940
const appColor = Object.freeze({
4041
primaryColor: '#00f',
@@ -52,6 +53,7 @@ describe('overrides', () => {
5253
logoUrl: 'mock://fake-url-for-org/logo.png',
5354
darkLogoUrl: 'mock://fake-url-for-org/dark-logo.png',
5455
} satisfies Branding);
56+
const organizationCustomCss = '.logto_main-content { background-color: #0f0 !important; }';
5557

5658
afterEach(async () => {
5759
await organizationApi.cleanUp();
@@ -64,6 +66,7 @@ describe('overrides', () => {
6466
privacyPolicyUrl: null,
6567
color: omniColor,
6668
branding: omniBranding,
69+
customCss: omniCustomCss,
6770
signUp: { identifiers: [], password: true, verify: false },
6871
signIn: {
6972
methods: [
@@ -234,11 +237,42 @@ describe('overrides', () => {
234237
await deleteApplication(application.id);
235238
});
236239

240+
it('should apply omni custom CSS', async () => {
241+
const experience = new ExpectExperience(await browser.newPage());
242+
await experience.navigateTo(demoAppUrl.href);
243+
const element = await experience.toMatchElement('main.logto_main-content');
244+
expect(
245+
await element.evaluate((element) => window.getComputedStyle(element).backgroundColor)
246+
).toBe('rgb(255, 0, 0)');
247+
248+
await experience.page.close();
249+
});
250+
251+
it('should apply organization-level custom CSS over omni custom CSS', async () => {
252+
const organization = await organizationApi.create({
253+
name: 'Sign-in experience override',
254+
});
255+
256+
await organizationApi.update(organization.id, {
257+
customCss: organizationCustomCss,
258+
});
259+
260+
const experience = new ExpectExperience(await browser.newPage());
261+
await experience.navigateTo(demoAppUrl.href + `?organization_id=${organization.id}`);
262+
const element = await experience.toMatchElement('main.logto_main-content');
263+
expect(
264+
await element.evaluate((element) => window.getComputedStyle(element).backgroundColor)
265+
).toBe('rgb(0, 255, 0)');
266+
267+
await experience.page.close();
268+
});
269+
237270
describe('override fallback', () => {
238271
beforeAll(async () => {
239272
await updateSignInExperience({
240273
color: omniColor,
241274
branding: pick(omniBranding, 'logoUrl', 'favicon'),
275+
customCss: omniCustomCss,
242276
});
243277
});
244278

@@ -301,4 +335,19 @@ describe('overrides', () => {
301335
await deleteApplication(application.id);
302336
await experience.page.close();
303337
});
338+
339+
it('should fallback to omni custom CSS when organization-level custom CSS is not provided', async () => {
340+
const organization = await organizationApi.create({
341+
name: 'Sign-in experience override',
342+
});
343+
344+
const experience = new ExpectExperience(await browser.newPage());
345+
await experience.navigateTo(demoAppUrl.href + `?organization_id=${organization.id}`);
346+
const element = await experience.toMatchElement('main.logto_main-content');
347+
expect(
348+
await element.evaluate((element) => window.getComputedStyle(element).backgroundColor)
349+
).toBe('rgb(255, 0, 0)');
350+
351+
await experience.page.close();
352+
});
304353
});

0 commit comments

Comments
 (0)