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: 1 addition & 2 deletions .github/workflows/js-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ jobs:
js-unit-tests:
runs-on: ubuntu-latest
timeout-minutes: 15
# TODO: remove continue-on-error after all test failures are fixed.
continue-on-error: true
continue-on-error: false
env:
TURBO_SCM_BASE: ${{ inputs.turbo_scm_base }}
TURBO_SCM_HEAD: ${{ inputs.turbo_scm_head }}
Expand Down
6 changes: 5 additions & 1 deletion PingTestRunner/__tests__/integration/device-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,11 @@ describe('@ping-identity/rn-device-client — integration', () => {
});
const mod = await loadDeviceClient(native);
const client = mod.createDeviceClient(VALID_CONFIG);
await expect(client.oath.get()).rejects.toEqual(nativeError);
await expect(client.oath.get()).rejects.toMatchObject({
code: nativeError.code,
message: nativeError.message,
status: nativeError.status,
});
});
});

Expand Down
78 changes: 78 additions & 0 deletions PingTestRunner/__tests__/integration/external-idp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ async function loadExternalIdp(nativeMock: NativeExternalIdpMock) {
return require('@ping-identity/rn-external-idp');
}

async function loadExternalIdpWithRealHelpers(
nativeMock: NativeExternalIdpMock,
) {
jest.resetModules();
jest.doMock(
'../../../packages/external-idp/src/NativeRNPingExternalIdp',
() => ({
...jest.requireActual(
'../../../packages/external-idp/src/NativeRNPingExternalIdp',
),
getNativeModule: jest.fn(() => nativeMock),
}),
);
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('@ping-identity/rn-external-idp');
}

describe('@ping-identity/rn-external-idp — integration', () => {
afterEach(() => jest.restoreAllMocks());

Expand Down Expand Up @@ -273,6 +290,67 @@ describe('@ping-identity/rn-external-idp — integration', () => {
});
});

// ─── fromNativeAuthorizeResult — real field validation ────────────────────
//
// Uses jest.requireActual so the real fromNativeAuthorizeResult runs instead of
// an identity stub. The helper reads .token and validates .additionalParameters,
// so a bridge-side field rename is caught here without a device or simulator.

describe('fromNativeAuthorizeResult — real field validation', () => {
it('extracts token from native result', async () => {
const mock = makeMock({
authorizeForJourney: jest.fn(async () => ({ token: 'tok-1' })),
});
const mod = await loadExternalIdpWithRealHelpers(mock);
const client = mod.createExternalIdpClient({});
const journey = { getId: jest.fn(async () => 'j-1') };
const result = await client.authorizeForJourney(journey);
expect(result.token).toBe('tok-1');
});

it('extracts token and additionalParameters from native result', async () => {
const mock = makeMock({
authorizeForJourney: jest.fn(async () => ({
token: 'tok-2',
additionalParameters: { key: 'val' },
})),
});
const mod = await loadExternalIdpWithRealHelpers(mock);
const client = mod.createExternalIdpClient({});
const journey = { getId: jest.fn(async () => 'j-2') };
const result = await client.authorizeForJourney(journey);
expect(result.token).toBe('tok-2');
expect(result.additionalParameters).toEqual({ key: 'val' });
});

it('throws when native result is missing token', async () => {
const mock = makeMock({
authorizeForJourney: jest.fn(async () => ({})),
});
const mod = await loadExternalIdpWithRealHelpers(mock);
const client = mod.createExternalIdpClient({});
const journey = { getId: jest.fn(async () => 'j-3') };
await expect(client.authorizeForJourney(journey)).rejects.toThrow(
'token must be a string',
);
});

it('throws when additionalParameters contains a non-string value', async () => {
const mock = makeMock({
authorizeForJourney: jest.fn(async () => ({
token: 'tok-4',
additionalParameters: { k: 123 },
})),
});
const mod = await loadExternalIdpWithRealHelpers(mock);
const client = mod.createExternalIdpClient({});
const journey = { getId: jest.fn(async () => 'j-4') };
await expect(client.authorizeForJourney(journey)).rejects.toThrow(
'additionalParameters.k must be a string',
);
});
});

// ─── selectProviderForJourney() ───────────────────────────────────────────

describe('selectProviderForJourney()', () => {
Expand Down
52 changes: 50 additions & 2 deletions PingTestRunner/__tests__/integration/native-spec-contracts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@

import type { Spec as BindingSpec } from '../../../packages/binding/src/NativeRNPingBinding';
import type { Spec as BrowserSpec } from '../../../packages/browser/src/NativeRNPingBrowser';
import type { Spec as DeviceClientSpec } from '../../../packages/device-client/src/NativeRNPingDeviceClient';
import type { Spec as DeviceIdSpec } from '../../../packages/device-id/src/NativeRNPingDeviceId';
import type { Spec as DeviceProfileSpec } from '../../../packages/device-profile/src/NativeRNPingDeviceProfile';
import type { Spec as ExternalIdpSpec } from '../../../packages/external-idp/src/NativeRNPingExternalIdp';
import type { Spec as FidoSpec } from '../../../packages/fido/src/NativeRNPingFido';
import type { Spec as JourneySpec } from '../../../packages/journey/src/NativeRNPingJourney';
import type { Spec as LoggerSpec } from '../../../packages/logger/src/NativeRNPingLogger';
import type { Spec as OathSpec } from '../../../packages/oath/src/NativeRNPingOath';
import type { Spec as OidcSpec } from '../../../packages/oidc/src/NativeRNPingOidc';
import type { Spec as PushSpec } from '../../../packages/push/src/NativeRNPingPush';
import type { Spec as StorageSpec } from '../../../packages/storage/src/NativeRNPingStorage';

// ─── rn-binding ─────────────────────────────────────────────────────────────
Expand All @@ -53,6 +56,13 @@ type _BindingMockedMethods = Pick<
// jest.setup.js mocks: configure, reset, open
type _BrowserMockedMethods = Pick<BrowserSpec, 'configure' | 'reset' | 'open'>;

// ─── rn-device-client ────────────────────────────────────────────────────────
// jest.setup.js mocks: create, get, update, deleteDevice, dispose
type _DeviceClientMockedMethods = Pick<
DeviceClientSpec,
'create' | 'get' | 'update' | 'deleteDevice' | 'dispose'
>;

// ─── rn-device-id ───────────────────────────────────────────────────────────
// jest.setup.js mocks: getDefaultDeviceId
type _DeviceIdMockedMethods = Pick<DeviceIdSpec, 'getDefaultDeviceId'>;
Expand All @@ -64,11 +74,22 @@ type _DeviceProfileMockedMethods = Pick<
'collectDeviceProfile' | 'collectDeviceProfileForJourney'
>;

// ─── rn-external-idp ─────────────────────────────────────────────────────────
// jest.setup.js mocks: authorizeForJourney, selectProviderForJourney
type _ExternalIdpMockedMethods = Pick<
ExternalIdpSpec,
'authorizeForJourney' | 'selectProviderForJourney'
>;

// ─── rn-fido ────────────────────────────────────────────────────────────────
// jest.setup.js mocks: registerCredential, authenticateCredential
// jest.setup.js mocks: registerCredential, authenticateCredential,
// registerCredentialForJourney, authenticateCredentialForJourney
type _FidoMockedMethods = Pick<
FidoSpec,
'registerCredential' | 'authenticateCredential'
| 'registerCredential'
| 'authenticateCredential'
| 'registerCredentialForJourney'
| 'authenticateCredentialForJourney'
>;

// ─── rn-journey ─────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -133,6 +154,33 @@ type _OidcMockedMethods = Pick<
| 'logout'
>;

// ─── rn-push ─────────────────────────────────────────────────────────────────
// jest.setup.js mocks: all 21 bridge methods
type _PushMockedMethods = Pick<
PushSpec,
| 'initialize'
| 'addCredentialFromUri'
| 'getCredential'
| 'getCredentials'
| 'saveCredential'
| 'deleteCredential'
| 'setDeviceToken'
| 'getDeviceToken'
| 'processNotification'
| 'processNotificationFromMessage'
| 'approveNotification'
| 'approveChallengeNotification'
| 'approveBiometricNotification'
| 'denyNotification'
| 'getPendingNotifications'
| 'getAllNotifications'
| 'getNotification'
| 'cleanupNotifications'
| 'close'
| 'consumePendingMessages'
| 'refreshToken'
>;

Comment thread
coderabbitai[bot] marked this conversation as resolved.
// ─── rn-storage ─────────────────────────────────────────────────────────────
// jest.setup.js mocks: registerSessionStorage, configureSessionStorage,
// registerOidcStorage, configureOidcStorage
Expand Down
6 changes: 3 additions & 3 deletions PingTestRunner/__tests__/integration/oath.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ describe('@ping-identity/rn-oath — integration', () => {
await client.close();
await expect(client.generateCode('cred-1')).rejects.toMatchObject({
type: 'state_error',
error: 'OATH_STATE_ERROR',
code: 'OATH_STATE_ERROR',
});
});
});
Expand Down Expand Up @@ -337,7 +337,7 @@ describe('configureOathPolicyEvaluator', () => {
}
expect(thrown).toMatchObject({
type: 'argument_error',
error: 'OATH_INVALID_PARAMETER',
code: 'OATH_INVALID_PARAMETER',
});
});

Expand All @@ -354,7 +354,7 @@ describe('configureOathPolicyEvaluator', () => {
}
expect(thrown).toMatchObject({
type: 'argument_error',
error: 'OATH_INVALID_PARAMETER',
code: 'OATH_INVALID_PARAMETER',
});
expect(native.registerOathPolicyEvaluator).not.toHaveBeenCalled();
});
Expand Down
Loading
Loading