Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions src/app/components/Account/AccountHeader/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ const idctaConfig: IdctaConfig = {
signout_url: 'https://example.com/signout',
foryou_url: 'https://example.com/foryou',
initialIsSignedIn: false,
identity: {
idSignedInCookieName: 'ckns_id',
},
};

const renderWithProviders = (overrides = {}) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ const idctaConfig: IdctaConfig = {
settings_url: 'https://example.com/settings',
signout_url: 'https://example.com/signout',
foryou_url: 'https://example.com/foryou',
identity: {
idSignedInCookieName: 'ckns_id',
},
} as unknown as IdctaConfig;

jest.mock('#app/hooks/useToggle');
Expand Down
23 changes: 0 additions & 23 deletions src/app/contexts/AccountContext/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { use } from 'react';
import onClient from '#app/lib/utilities/onClient';
import { IdctaConfig } from '#app/models/types/account';
import Cookie from 'js-cookie';
import { AccountContext } from '.';
import {
render,
screen,
waitFor,
} from '../../components/react-testing-library-with-providers';

jest.mock('#app/lib/utilities/onClient');

const mockIdctaConfig = {
'id-availability': 'GREEN',
signin_url: 'https://example.com/signin',
Expand All @@ -21,15 +17,11 @@ const mockIdctaConfig = {
foryou_url: 'https://example.com/foryou',
unavailable_url: 'https://example.com/unavailable',
initialIsSignedIn: true,
identity: {
idSignedInCookieName: 'ckns_id',
},
} as IdctaConfig;

describe('AccountContext', () => {
beforeEach(() => {
jest.clearAllMocks();
(onClient as jest.Mock).mockReturnValue(true);

delete (window as any).location;
window.location = { href: 'https://example.com/current-page' } as any;
Expand Down Expand Up @@ -176,21 +168,6 @@ describe('AccountContext', () => {
expect(context.isSignedIn).toBe(false);
});

it('should set isSignedIn to true when ckns_id cookie is present', () => {
jest.spyOn(Cookie, 'get').mockReturnValue('ckns_id_cookie_value' as any);

render(<TestComponent />, {
idctaConfig: { ...mockIdctaConfig, initialIsSignedIn: false },
service: 'hindi',
});

const testEl = screen.getByTestId('test-component');
const context = JSON.parse(testEl.textContent as string);

expect(Cookie.get).toHaveBeenCalledWith('ckns_id');
expect(context.isSignedIn).toBe(true);
});

it('should handle null initialConfig gracefully', () => {
render(<TestComponent />, {
idctaConfig: null,
Expand Down
15 changes: 1 addition & 14 deletions src/app/contexts/AccountContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { AccountContextProps, IdctaConfig } from '#app/models/types/account';
import appendCtaQueryParams from '#app/lib/idcta/appendCtaQueryParams';
import { ServiceContext } from '#app/contexts/ServiceContext';
import { RequestContext } from '#app/contexts/RequestContext';
import onClient from '#app/lib/utilities/onClient';
import Cookie from 'js-cookie';
import { getIdctaUserOrigin } from '#app/lib/idcta/getIDCTAUserOrigin';

export const AccountContext = createContext<AccountContextProps>(
Expand All @@ -22,10 +20,6 @@ type AccountProviderProps = {
initialConfig: IdctaConfig | null;
};

const getSignedInCookie = (cookieName = 'ckns_id') => {
return onClient() ? Cookie.get(cookieName) : false;
};

export const AccountProvider = ({
children,
initialConfig,
Expand Down Expand Up @@ -62,15 +56,8 @@ export const AccountProvider = ({
const signOutUrl = buildAccountUrl(initialConfig?.signout_url);
const forYouUrl = buildAccountUrl(initialConfig?.foryou_url);

// TODO: initialIsSignedIn is always false in test/live env due to filtered cookie header,
// it will be improved to detect signed-in status server side in the future
// Ticket: https://bbc.atlassian.net/browse/WS-2388
const clientSignedInState = getSignedInCookie(
initialConfig?.identity?.idSignedInCookieName,
);
const isSignedIn =
isIdctaAvailable &&
Boolean(initialConfig?.initialIsSignedIn || clientSignedInState);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should still keep the client side fallback?
e.g. if for some reason the x-id-oidc-signedi hint header is missing, it would disable IDCTA/UAS functionality.

WDYT? cc @jinidev

isIdctaAvailable && Boolean(initialConfig?.initialIsSignedIn);

const value = useMemo(
() => ({
Expand Down
32 changes: 32 additions & 0 deletions src/app/lib/idcta/getIdctaConfig/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,36 @@ describe('getIdctaConfig', () => {

expect(result).toBeNull();
});

it('should set initialIsSignedIn to true when x-id-oidc-signedin header is "1"', async () => {
mockFetchIdctaConfig.mockResolvedValue(mockIdctaConfig);

const result = await getIdctaConfig(mockToggles, mockService, '1');

expect(result?.initialIsSignedIn).toBe(true);
});

it('should set initialIsSignedIn to false when x-id-oidc-signedin header is "0"', async () => {
mockFetchIdctaConfig.mockResolvedValue(mockIdctaConfig);

const result = await getIdctaConfig(mockToggles, mockService, '0');

expect(result?.initialIsSignedIn).toBe(false);
});

it('should set initialIsSignedIn to false when x-id-oidc-signedin header is absent', async () => {
mockFetchIdctaConfig.mockResolvedValue(mockIdctaConfig);

const result = await getIdctaConfig(mockToggles, mockService);

expect(result?.initialIsSignedIn).toBe(false);
});

it('should set initialIsSignedIn to false when x-id-oidc-signedin header has an invalid value', async () => {
mockFetchIdctaConfig.mockResolvedValue(mockIdctaConfig);

const result = await getIdctaConfig(mockToggles, mockService, 'invalid');

expect(result?.initialIsSignedIn).toBe(false);
});
});
13 changes: 3 additions & 10 deletions src/app/lib/idcta/getIdctaConfig/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import getToggleDefinitions from '#app/lib/utilities/getToggleDefinition';
import isLocal from '#app/lib/utilities/isLocal';
import { IdctaConfig } from '#app/models/types/account';
import { Toggles, Services } from '#app/models/types/global';
import hasCookie from '#app/lib/utilities/hasCookie';
import fetchIdctaConfig from '../fetchIdctaConfig';

const logger = nodeLogger(__filename);
Expand All @@ -12,13 +11,13 @@ const logger = nodeLogger(__filename);
* Gets IDCTA config with toggle validation and config verification
* @param toggles - Feature toggles
* @param service - Service name
* @param cookieHeader - Cookie header from request
* @param signedInHeader - Value of x-id-oidc-signedin header forwarded by Belfrage
* @returns Validated IdctaConfig with initialIsSignedIn or null
*/
export default async function getIdctaConfig(
toggles: Toggles,
service: Services,
cookieHeader?: string,
signedInHeader?: string,
): Promise<IdctaConfig | null> {
const toggleDefinitions = getToggleDefinitions(toggles);
const { enabled: isAccountEnabled, value: accountService = '' } =
Expand Down Expand Up @@ -47,12 +46,6 @@ export default async function getIdctaConfig(
return null;
}

const cookieName = config?.identity?.idSignedInCookieName;
const initialIsSignedIn = Boolean(
cookieHeader && cookieName
? hasCookie(cookieHeader, cookieName)
: undefined,
);

const initialIsSignedIn = signedInHeader === '1';
return { ...config, initialIsSignedIn };
}
3 changes: 0 additions & 3 deletions src/app/models/types/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ export type IdctaConfig = {
signout_url: string;
foryou_url: string;
initialIsSignedIn?: boolean;
identity: {
idSignedInCookieName: string;
};
};

export type AccountContextProps = {
Expand Down
7 changes: 4 additions & 3 deletions ws-nextjs-app/pages/_app.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,12 @@ export default class CustomApp extends App<Props> {
? (navResult.value?.data?.items ?? null)
: null;

const cookieHeader = ctx.req?.headers?.cookie;
const idctaResult = await getIdctaConfig(toggles, service, cookieHeader);
const signedInHeader = ctx.req?.headers?.['x-id-oidc-signedin'] as
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: Should we pass the ctx.req?.headers as requestHeaders to the getIdctaConfig? Then we could handle it properly without type casting

| string
| undefined;
const idctaResult = await getIdctaConfig(toggles, service, signedInHeader);
const pageType =
(ctx.req?.headers['page-type'] as PageTypes) || derivePageType(asPath);

const serverSideExperiments = getServerExperiments({
headers: ctx.req?.headers || {},
service,
Expand Down
Loading