Skip to content

Commit

Permalink
release(required): Amplify JS release (#14091)
Browse files Browse the repository at this point in the history
  • Loading branch information
Samaritan1011001 authored Dec 19, 2024
2 parents 74894a0 + 29b6c3f commit eb5cb51
Show file tree
Hide file tree
Showing 30 changed files with 786 additions and 245 deletions.
18 changes: 17 additions & 1 deletion .github/integ-config/integ-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,23 @@ tests:
sample_name: [subdomains]
spec: subdomains
browser: [chrome]

- test_name: integ_next_custom_auth
desc: 'Sign-in with Custom Auth flow'
framework: next
category: auth
sample_name: [custom-auth]
spec: custom-auth
browser: *minimal_browser_list
- test_name: integ_next_auth_sign_in_with_sms_mfa
desc: 'Resumable sign in with SMS MFA flow'
framework: next
category: auth
sample_name: [mfa]
spec: sign-in-resumable-mfa
browser: *minimal_browser_list
env:
NEXT_PUBLIC_BACKEND_CONFIG: resum-signin

# DISABLED Angular/Vue tests:
# TODO: delete tests or add custom ui logic to support them.

Expand Down
13 changes: 5 additions & 8 deletions .github/workflows/callable-canary-sampleapp-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ jobs:
working-directory: amplify-js-samples-staging/samples/next/auth/new-next-app
- name: Copy files from samples staging repo
run: |
rm -r ./samples/next/auth/new-next-app
rm -r ./samples/next/auth/new-next-app
cp -r ./samples/next/auth/auth-rsc ./samples/next/auth/new-next-app
working-directory: amplify-js-samples-staging
- name: Copy test file from samples staging repo
Expand All @@ -124,10 +124,8 @@ jobs:
- name: Install dependencies
run: npm install
working-directory: amplify-js-samples-staging/samples/next/auth/new-next-app
- name: Install amplify
run: |
npm install -g npm@latest
npm install aws-amplify -legacy-peer-deps
- name: Install latest stable amplify version
run: npm install aws-amplify@latest @aws-amplify/adapter-nextjs@latest
working-directory: amplify-js-samples-staging/samples/next/auth/new-next-app
- name: Start application and run test
run: |
Expand Down Expand Up @@ -186,15 +184,14 @@ jobs:
working-directory: amplify-js-samples-staging/samples/javascript/datastore
- name: Install amplify
run: |
npm install -g npm@latest
npm install aws-amplify -legacy-peer-deps
npm install aws-amplify@latest
working-directory: amplify-js-samples-staging/samples/javascript/datastore/new-javascript-app
- name: Remove existing src folder
run: rm -rf src
working-directory: amplify-js-samples-staging/samples/javascript/datastore/new-javascript-app
- name: Copy files from samples staging repo
run: |
rm -r ./samples/javascript/datastore/new-javascript-app
rm -r ./samples/javascript/datastore/new-javascript-app
cp -r ./samples/javascript/datastore/basic-crud ./samples/javascript/datastore/new-javascript-app
working-directory: amplify-js-samples-staging
- name: Copy test file from samples staging repo
Expand Down
23 changes: 22 additions & 1 deletion packages/adapter-nextjs/__tests__/createServerRunner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const mockAmplifyConfig: ResourcesConfig = {
},
},
};

jest.mock(
'../src/utils/createCookieStorageAdapterFromNextServerContext',
() => ({
Expand All @@ -30,6 +29,7 @@ jest.mock(

describe('createServerRunner', () => {
let createServerRunner: any;
let createRunWithAmplifyServerContextSpy: any;

const mockParseAmplifyConfig = jest.fn();
const mockCreateAWSCredentialsAndIdentityIdProvider = jest.fn();
Expand All @@ -50,11 +50,16 @@ describe('createServerRunner', () => {
jest.doMock('@aws-amplify/core/internals/utils', () => ({
parseAmplifyConfig: mockParseAmplifyConfig,
}));
createRunWithAmplifyServerContextSpy = jest.spyOn(
require('../src/utils/createRunWithAmplifyServerContext'),
'createRunWithAmplifyServerContext',
);

({ createServerRunner } = require('../src'));
});

afterEach(() => {
createRunWithAmplifyServerContextSpy.mockClear();
mockParseAmplifyConfig.mockClear();
mockCreateAWSCredentialsAndIdentityIdProvider.mockClear();
mockCreateKeyValueStorageFromCookieStorageAdapter.mockClear();
Expand Down Expand Up @@ -98,6 +103,10 @@ describe('createServerRunner', () => {
{},
operation,
);
expect(createRunWithAmplifyServerContextSpy).toHaveBeenCalledWith({
config: mockAmplifyConfigWithoutAuth,
tokenValidator: undefined,
});
});
});

Expand All @@ -120,6 +129,12 @@ describe('createServerRunner', () => {
mockAmplifyConfig.Auth,
sharedInMemoryStorage,
);
expect(createRunWithAmplifyServerContextSpy).toHaveBeenCalledWith({
config: mockAmplifyConfig,
tokenValidator: expect.objectContaining({
getItem: expect.any(Function),
}),
});
});
});

Expand Down Expand Up @@ -162,6 +177,12 @@ describe('createServerRunner', () => {
mockAmplifyConfig.Auth,
mockCookieStorageAdapter,
);
expect(createRunWithAmplifyServerContextSpy).toHaveBeenCalledWith({
config: mockAmplifyConfig,
tokenValidator: expect.objectContaining({
getItem: expect.any(Function),
}),
});
});
});
});
Expand Down
151 changes: 87 additions & 64 deletions packages/adapter-nextjs/__tests__/utils/createTokenValidator.test.ts
Original file line number Diff line number Diff line change
@@ -1,85 +1,108 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { CognitoJwtVerifier } from 'aws-jwt-verify';

import { isValidCognitoToken } from '../../src/utils/isValidCognitoToken';
import { createTokenValidator } from '../../src/utils/createTokenValidator';
import { JwtVerifier } from '../../src/types';

jest.mock('aws-jwt-verify');
jest.mock('../../src/utils/isValidCognitoToken');

const mockIsValidCognitoToken = isValidCognitoToken as jest.Mock;

const userPoolId = 'userPoolId';
const userPoolClientId = 'clientId';
const tokenValidatorInput = {
userPoolId,
userPoolClientId,
};
const accessToken = {
key: 'CognitoIdentityServiceProvider.clientId.usersub.accessToken',
value:
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMTEiLCJpc3MiOiJodHRwc',
};
const idToken = {
key: 'CognitoIdentityServiceProvider.clientId.usersub.idToken',
value: 'eyJzdWIiOiIxMTEiLCJpc3MiOiJodHRwc.XAiOiJKV1QiLCJhbGciOiJIUzI1NiJ',
};

const tokenValidator = createTokenValidator({
userPoolId,
userPoolClientId,
});
describe('createTokenValidator', () => {
const userPoolId = 'userPoolId';
const userPoolClientId = 'clientId';
const accessToken = {
key: 'CognitoIdentityServiceProvider.clientId.usersub.accessToken',
value: 'access-token-value',
};
const idToken = {
key: 'CognitoIdentityServiceProvider.clientId.usersub.idToken',
value: 'id-token-value',
};

const mockIsValidCognitoToken = jest.mocked(isValidCognitoToken);
const mockCognitoJwtVerifier = {
create: jest.mocked(CognitoJwtVerifier.create),
};

describe('Validator', () => {
afterEach(() => {
jest.resetAllMocks();
});
it('should return a validator', () => {
expect(createTokenValidator(tokenValidatorInput)).toBeDefined();
mockIsValidCognitoToken.mockClear();
});

it('should return true for non-token keys', async () => {
const result = await tokenValidator.getItem?.('mockKey', 'mockValue');
expect(result).toBe(true);
expect(mockIsValidCognitoToken).toHaveBeenCalledTimes(0);
it('should return a token validator', () => {
expect(
createTokenValidator({
userPoolId,
userPoolClientId,
}),
).toStrictEqual({
getItem: expect.any(Function),
});
});

it('should return true for valid accessToken', async () => {
mockIsValidCognitoToken.mockImplementation(() => Promise.resolve(true));

const result = await tokenValidator.getItem?.(
accessToken.key,
accessToken.value,
);

expect(result).toBe(true);
expect(mockIsValidCognitoToken).toHaveBeenCalledTimes(1);
expect(mockIsValidCognitoToken).toHaveBeenCalledWith({
userPoolId,
clientId: userPoolClientId,
token: accessToken.value,
tokenType: 'access',
describe('created token validator', () => {
afterEach(() => {
mockCognitoJwtVerifier.create.mockReset();
});
});

it('should return true for valid idToken', async () => {
mockIsValidCognitoToken.mockImplementation(() => Promise.resolve(true));

const result = await tokenValidator.getItem?.(idToken.key, idToken.value);
expect(result).toBe(true);
expect(mockIsValidCognitoToken).toHaveBeenCalledTimes(1);
expect(mockIsValidCognitoToken).toHaveBeenCalledWith({
userPoolId,
clientId: userPoolClientId,
token: idToken.value,
tokenType: 'id',
it('should return true if key is not for access or id tokens', async () => {
const tokenValidator = createTokenValidator({
userPoolId,
userPoolClientId,
});

expect(await tokenValidator.getItem?.('key', 'value')).toBe(true);
expect(mockIsValidCognitoToken).not.toHaveBeenCalled();
});
});

it('should return false if invalid tokenType is access', async () => {
mockIsValidCognitoToken.mockImplementation(() => Promise.resolve(false));
it('should return false if validator created without user pool or client ids', async () => {
const tokenValidator = createTokenValidator({});

const result = await tokenValidator.getItem?.(idToken.key, idToken.value);
expect(result).toBe(false);
expect(mockIsValidCognitoToken).toHaveBeenCalledTimes(1);
expect(
await tokenValidator.getItem?.(accessToken.key, accessToken.value),
).toBe(false);
expect(await tokenValidator.getItem?.(idToken.key, idToken.value)).toBe(
false,
);
expect(mockIsValidCognitoToken).not.toHaveBeenCalled();
});

describe.each([
{ tokenUse: 'access', token: accessToken },
{ tokenUse: 'id', token: idToken },
])('$tokenUse token verifier', ({ tokenUse, token }) => {
const mockTokenVerifier = {} as JwtVerifier;
const tokenValidator = createTokenValidator({
userPoolId,
userPoolClientId,
});

beforeAll(() => {
mockCognitoJwtVerifier.create.mockReturnValue(mockTokenVerifier);
});

it('should create a jwt verifier and use it to validate', async () => {
await tokenValidator.getItem?.(token.key, token.value);

expect(mockCognitoJwtVerifier.create).toHaveBeenCalledWith({
userPoolId,
clientId: userPoolClientId,
tokenUse,
});
expect(mockIsValidCognitoToken).toHaveBeenCalledWith({
token: token.value,
verifier: mockTokenVerifier,
});
});

it('should not re-create the jwt verifier', async () => {
await tokenValidator.getItem?.(token.key, token.value);

expect(mockCognitoJwtVerifier.create).not.toHaveBeenCalled();
expect(mockIsValidCognitoToken).toHaveBeenCalled();
});
});
});
});
Loading

0 comments on commit eb5cb51

Please sign in to comment.