Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release(required): Amplify JS release #13814

Merged
merged 5 commits into from
Sep 16, 2024
Merged
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
26 changes: 16 additions & 10 deletions .github/actions/load-verdaccio-with-amplify-js/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ runs:
steps:
- name: Start verdaccio
run: |
npx [email protected] &
# This version supports Node.js v22
npx [email protected] &
while ! nc -z localhost 4873; do
echo "Verdaccio not running yet"
sleep 1
Expand All @@ -18,25 +19,30 @@ runs:
- name: Install and run npm-cli-login
shell: bash
env:
NPM_REGISTRY: http://localhost:4873/
NPM_REGISTRY_HOST: localhost:4873
NPM_REGISTRY: http://localhost:4873
NPM_USER: verdaccio
NPM_PASS: verdaccio
NPM_EMAIL: [email protected]
run: |
npm i -g npm-cli-adduser
npm-cli-adduser
sleep 1
- name: Configure registry and git
# Make the HTTP request that npm addUser makes to avoid the "Exit handler never called" error
TOKEN=$(curl -s \
-H "Accept: application/json" \
-H "Content-Type:application/json" \
-X PUT --data "{\"name\": \"$NPM_USER\", \"password\": \"$NPM_PASS\", \"email\": \"$NPM_EMAIL\"}" \
$NPM_REGISTRY/-/user/org.couchdb.user:$NPM_USER 2>&1 | jq -r '.token')

# Set the Verdaccio registry and set the token for logging in
yarn config set registry $NPM_REGISTRY
npm set registry $NPM_REGISTRY
npm set //"$NPM_REGISTRY_HOST"/:_authToken $TOKEN
- name: Configure git
shell: bash
working-directory: ./amplify-js
env:
NPM_REGISTRY: http://localhost:4873/
NPM_USER: verdaccio
NPM_PASS: verdaccio
NPM_EMAIL: [email protected]
run: |
yarn config set registry $NPM_REGISTRY
npm set registry $NPM_REGISTRY
git config --global user.email $NPM_EMAIL
git config --global user.name $NPM_USER
git status
Expand Down
6 changes: 4 additions & 2 deletions .github/actions/node-and-build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ inputs:
is-prebuild:
required: false
default: false
node_version:
required: false
runs:
using: 'composite'
steps:
- name: Setup Node.js 18
- name: Setup Node.js
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version: 18.20.2
node-version: ${{ inputs.node_version || '18.x' }}
env:
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 2
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
Expand Down
7 changes: 7 additions & 0 deletions .github/integ-config/integ-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -870,3 +870,10 @@ tests:
spec: ssr-context-isolation
yarn_script: ci:ssr-context-isolation
browser: [chrome]
- test_name: integ_node_envs
desc: 'Node.js environment tests'
framework: node
category: integration
sample_name: auth-gql-storage
yarn_script: ci:node-env-test
node_versions: ['18.x', '20.x', '22.x']
7 changes: 7 additions & 0 deletions .github/workflows/callable-e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ on:
yarn_script:
required: false
type: string
node_versions:
required: false
type: string

env:
AMPLIFY_DIR: /home/runner/work/amplify-js/amplify-js/amplify-js
Expand All @@ -54,6 +57,8 @@ jobs:
- ${{ fromJson(inputs.browser) }}
sample_name:
- ${{ fromJson(inputs.sample_name) }}
node_version:
- ${{ fromJson(inputs.node_versions) }}
fail-fast: false
timeout-minutes: ${{ inputs.timeout_minutes }}

Expand All @@ -64,6 +69,8 @@ jobs:
path: amplify-js
- name: Setup node and build the repository
uses: ./amplify-js/.github/actions/node-and-build
with:
node_version: ${{ matrix.node_version }}
- name: Setup samples staging repository
uses: ./amplify-js/.github/actions/setup-samples-staging
with:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/callable-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ jobs:
timeout_minutes: ${{ matrix.integ-config.timeout_minutes || 35 }}
retry_count: ${{ matrix.integ-config.retry_count || 3 }}
yarn_script: ${{ matrix.integ-config.yarn_script || '' }}
node_versions: ${{ toJSON(matrix.integ-config.node_versions) || '[""]' }}

# e2e-test-runner-headless:
# name: E2E test runnner_headless
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@
"webpack-bundle-analyzer": "^4.7.0",
"webpack-cli": "^5.0.0"
},
"engines": {
"node": ">=18"
},
"resolutions": {
"@types/babel__traverse": "7.20.0",
"path-scurry": "1.10.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/api-graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
"dependencies": {
"@aws-amplify/api-rest": "4.0.47",
"@aws-amplify/core": "6.4.0",
"@aws-amplify/data-schema": "^1.0.0",
"@aws-amplify/data-schema": "^1.5.0",
"@aws-sdk/types": "3.387.0",
"graphql": "15.8.0",
"rxjs": "^7.8.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { AmplifyUrl } from '@aws-amplify/core/internals/utils';

import { cognitoUserPoolEndpointResolver } from '../../src/foundation/cognitoUserPoolEndpointResolver';
import { COGNITO_IDP_SERVICE_NAME } from '../../src/foundation/constants';

describe('cognitoUserPoolEndpointResolver', () => {
it('should return the Cognito User Pool endpoint', () => {
const region = 'us-west-2';
const { url } = cognitoUserPoolEndpointResolver({ region });

expect(url instanceof AmplifyUrl).toBe(true);
expect(url.toString()).toEqual(
`https://${COGNITO_IDP_SERVICE_NAME}.us-west-2.amazonaws.com/`,
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers';

import * as serviceClients from '../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider';
import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from '../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/constants';

import { mockServiceClientAPIConfig } from './testUtils/data';

jest.mock('@aws-amplify/core/internals/aws-client-utils/composers', () => ({
...jest.requireActual(
'@aws-amplify/core/internals/aws-client-utils/composers',
),
composeServiceApi: jest.fn(),
}));

export const mockComposeServiceApi = jest.mocked(composeServiceApi);

describe('service clients', () => {
const serviceClientFactories = Object.keys(serviceClients);

afterEach(() => {
mockComposeServiceApi.mockClear();
});

test.each(serviceClientFactories)(
'factory `%s` should invoke composeServiceApi with expected parameters',
serviceClientFactory => {
// eslint-disable-next-line import/namespace
serviceClients[serviceClientFactory](mockServiceClientAPIConfig);

expect(mockComposeServiceApi).toHaveBeenCalledWith(
expect.any(Function),
expect.any(Function),
expect.any(Function),
expect.objectContaining({
...DEFAULT_SERVICE_CLIENT_API_CONFIG,
...mockServiceClientAPIConfig,
}),
);
},
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { unauthenticatedHandler } from '@aws-amplify/core/internals/aws-client-utils';
import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers';

import { cognitoUserPoolTransferHandler } from '../../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler';

jest.mock('@aws-amplify/core/internals/aws-client-utils/composers');
jest.mock('@aws-amplify/core/internals/aws-client-utils');

const mockComposeTransferHandler = jest.mocked(composeTransferHandler);
const mockUnauthenticatedHandler = jest.mocked(unauthenticatedHandler);

describe('cognitoUserPoolTransferHandler', () => {
beforeAll(() => {
// need to make sure cognitoUserPoolTransferHandler is imported and used in
// the scope of the test
const _ = cognitoUserPoolTransferHandler;
});

it('adds the disableCacheMiddlewareFactory at module loading', () => {
expect(mockComposeTransferHandler).toHaveBeenCalledTimes(1);

const [core, middleware] = mockComposeTransferHandler.mock.calls[0];

expect(core).toStrictEqual(mockUnauthenticatedHandler);
expect(middleware).toHaveLength(1);

const disableCacheMiddlewareFactory = middleware[0] as any;
const disableCacheMiddlewarePendingNext = disableCacheMiddlewareFactory();

const mockNext = jest.fn();
const disableCacheMiddleware = disableCacheMiddlewarePendingNext(mockNext);
const mockRequest = {
headers: {},
};

disableCacheMiddleware(mockRequest);

expect(mockNext).toHaveBeenCalledWith(mockRequest);
expect(mockRequest.headers).toEqual({
'cache-control': 'no-store',
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {
HttpResponse,
parseJsonError,
} from '@aws-amplify/core/internals/aws-client-utils';

import { createEmptyResponseDeserializer } from '../../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createEmptyResponseDeserializer';
import { AuthError } from '../../../../../../../src/errors/AuthError';

jest.mock('@aws-amplify/core/internals/aws-client-utils');

const mockParseJsonError = jest.mocked(parseJsonError);

describe('createEmptyResponseDeserializer created response deserializer', () => {
const deserializer = createEmptyResponseDeserializer();

it('returns undefined for 2xx status code', async () => {
const response: HttpResponse = {
statusCode: 200,
body: {
json: () => Promise.resolve({}),
blob: () => Promise.resolve(new Blob()),
text: () => Promise.resolve(''),
},
headers: {},
};
const output = await deserializer(response);

expect(output).toBeUndefined();
});

it('throws AuthError for 4xx status code', async () => {
const expectedErrorName = 'TestError';
const expectedErrorMessage = 'TestErrorMessage';
const expectedError = new Error(expectedErrorMessage);
expectedError.name = expectedErrorName;

mockParseJsonError.mockReturnValueOnce(expectedError as any);
const response: HttpResponse = {
statusCode: 400,
body: {
json: () => Promise.resolve({}),
blob: () => Promise.resolve(new Blob()),
text: () => Promise.resolve(''),
},
headers: {},
};

expect(deserializer(response as any)).rejects.toThrow(
new AuthError({
name: expectedErrorName,
message: expectedErrorMessage,
}),
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
HttpResponse,
parseJsonBody,
parseJsonError,
} from '@aws-amplify/core/internals/aws-client-utils';

import { createUserPoolDeserializer } from '../../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer';
import { AuthError } from '../../../../../../../src/errors/AuthError';

jest.mock('@aws-amplify/core/internals/aws-client-utils');

const mockParseJsonBody = jest.mocked(parseJsonBody);
const mockParseJsonError = jest.mocked(parseJsonError);

describe('buildUserPoolDeserializer created response deserializer', () => {
const deserializer = createUserPoolDeserializer();

it('returns body for 2xx status code', async () => {
const expectedBody = { test: 'test' };
mockParseJsonBody.mockResolvedValueOnce(expectedBody);
const response: HttpResponse = {
statusCode: 200,
body: {
json: () => Promise.resolve({}),
blob: () => Promise.resolve(new Blob()),
text: () => Promise.resolve(''),
},
headers: {},
};
const output = await deserializer(response);

expect(output).toStrictEqual(expectedBody);
});

it('throws AuthError for 4xx status code', async () => {
const expectedErrorName = 'TestError';
const expectedErrorMessage = 'TestErrorMessage';
const expectedError = new Error(expectedErrorMessage);
expectedError.name = expectedErrorName;

mockParseJsonError.mockReturnValueOnce(expectedError as any);
const response: HttpResponse = {
statusCode: 400,
body: {
json: () => Promise.resolve({}),
blob: () => Promise.resolve(new Blob()),
text: () => Promise.resolve(''),
},
headers: {},
};

expect(deserializer(response as any)).rejects.toThrow(
new AuthError({
name: expectedErrorName,
message: expectedErrorMessage,
}),
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { AmplifyUrl } from '@aws-amplify/core/internals/utils';

import { createUserPoolSerializer } from '../../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolSerializer';

describe('createUserPoolSerializer created request serializer', () => {
test.each(['SignUp', 'InitiateAuth', 'RevokeToken'] as const)(
`it serializes requests from operation %s`,
operation => {
const testInput = { testBody: 'testBody' };
const testEndpoint = {
url: new AmplifyUrl('http://test.com'),
};
const serializer = createUserPoolSerializer(operation);
const result = serializer(testInput, testEndpoint);

expect(result).toEqual({
method: 'POST',
url: testEndpoint.url,
headers: {
'content-type': 'application/x-amz-json-1.1',
'x-amz-target': `AWSCognitoIdentityProviderService.${operation}`,
},
body: JSON.stringify(testInput),
});
},
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ServiceClientFactoryInput } from '../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/types';

export const mockServiceClientAPIConfig: ServiceClientFactoryInput = {
endpointResolver: jest.fn() as jest.MockedFunction<
ServiceClientFactoryInput['endpointResolver']
>,
};
Loading
Loading