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

feat(auth): adds hub events to updateUserAttributes api #10731

Merged
merged 14 commits into from Dec 7, 2022
Merged
Expand Up @@ -1657,4 +1657,39 @@ describe('refreshSession()', () => {
new Error('Username is null. Cannot retrieve a new session')
);
});

test('update attributes usage of three out of three parameters in callback', () => {
const codeDeliverDetailsResult = {
'CodeDeliveryDetailsList': [
{
'AttributeName': 'email',
'DeliveryMedium': 'EMAIL',
'Destination': 'e***@e***'
}
]
};
const spyon = jest.spyOn(CognitoUser.prototype, 'updateAttributes')
.mockImplementationOnce((attrs, callback) => {
callback(null, 'SUCCESS', codeDeliverDetailsResult);
Comment on lines +1671 to +1673
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as the other, this is testing the mock not the actual code look on this one
https://github.com/aws-amplify/amplify-js/blob/main/packages/amazon-cognito-identity-js/__tests__/CognitoUser.test.js#L384

});
const attrs = [
{
Name: 'email',
Value: 'email@email.com'
},
{
Name: 'family_name',
Value: 'familyName'
}
];
cognitoUser.updateAttributes(
attrs,
(err, result, details) => {
expect(err).toBe(null);
expect(result).toBe('SUCCESS');
expect(details).toBe(codeDeliverDetailsResult);
}
);
spyon.mockClear();
});
});
3 changes: 2 additions & 1 deletion packages/amazon-cognito-identity-js/index.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/amazon-cognito-identity-js/src/CognitoUser.js
Expand Up @@ -1125,13 +1125,13 @@ export default class CognitoUser {
UserAttributes: attributes,
ClientMetadata: clientMetadata,
},
err => {
(err,result) => {
if (err) {
return callback(err, null);
}

// update cached user
return this.getUserData(() => callback(null, 'SUCCESS'), {
helgabalashova marked this conversation as resolved.
Show resolved Hide resolved
return this.getUserData(() => callback(null, 'SUCCESS', result), {
bypassCache: true,
});
}
Expand Down
96 changes: 96 additions & 0 deletions packages/auth/__tests__/auth-unit-test.ts
Expand Up @@ -2995,6 +2995,102 @@ describe('auth unit test', () => {
);
spyon.mockClear();
});

test('error hub event', async (done) => {
expect.assertions(3);
const spyon = jest.spyOn(CognitoUser.prototype, 'updateAttributes')
.mockImplementationOnce((attrs, callback: any) => {
callback(new Error('Error'), null, null);
});

const auth = new Auth(authOptions);

const user = new CognitoUser({
Username: 'username',
Pool: userPool,
});

const attributes = {
email: 'email',
phone_number: 'phone_number',
sub: 'sub',
};

const listenToHub = Hub.listen('auth', ({ payload }) => {
const { event } = payload;
if (event === 'updateUserAttributes_failure') {
expect(payload.data.message).toBe('Error');
expect(payload.message).toBe('Failed to update attributes');
listenToHub();
done();
}
});

try {
await auth.updateUserAttributes(user, attributes);
} catch (e) {
expect(e).toEqual(new Error('Error'));
}

spyon.mockClear();
});

test('happy case code delivery details hub event', async (done) => {
expect.assertions(2);

const codeDeliverDetailsResult: any = {
'CodeDeliveryDetailsList': [
{
'AttributeName': 'email',
'DeliveryMedium': 'EMAIL',
'Destination': 'e***@e***'
}
]
};
const spyon = jest.spyOn(CognitoUser.prototype, 'updateAttributes')
.mockImplementationOnce((attrs, callback: any) => {
callback(null, 'SUCCESS', codeDeliverDetailsResult);
});
const auth = new Auth(authOptions);

const user = new CognitoUser({
Username: 'username',
Pool: userPool,
});

const attributes = {
email: 'email',
phone_number: 'phone_number',
sub: 'sub',
};
const payloadData = {
'email': {
isUpdated: false,
codeDeliveryDetails: {
AttributeName: 'email',
DeliveryMedium: 'EMAIL',
Destination: 'e***@e***'
}
},
'phone_number': {
isUpdated: true
},
'sub': {
isUpdated: true
}
};
const listenToHub = Hub.listen('auth', ({ payload }) => {
const { event } = payload;
if (event === 'updateUserAttributes') {
expect(payload.data).toEqual(payloadData);
listenToHub();
done();
}
});

expect(await auth.updateUserAttributes(user, attributes)).toBe('SUCCESS');
spyon.mockClear();
});
});

describe('deleteUserAttributes test', () => {
Expand Down
28 changes: 27 additions & 1 deletion packages/auth/src/Auth.ts
Expand Up @@ -53,6 +53,7 @@ import {
CognitoRefreshToken,
CognitoAccessToken,
NodeCallback,
CodeDeliveryDetails,
} from 'amazon-cognito-identity-js';

import { parse } from 'url';
Expand Down Expand Up @@ -1424,10 +1425,16 @@ export class AuthClass {
}
user.updateAttributes(
attributeList,
(err, result) => {
(err, result, details) => {

if (err) {
dispatchAuthEvent('updateUserAttributes_failure', err, 'Failed to update attributes');
return reject(err);
} else {
const attrs = this.createUpdateAttributesResultList(
attributes as Record<string, string>, details?.CodeDeliveryDetailsList
);
dispatchAuthEvent('updateUserAttributes', attrs, 'Attributes successfully updated');
return resolve(result);
}
},
Expand All @@ -1436,6 +1443,25 @@ export class AuthClass {
});
});
}

private createUpdateAttributesResultList(
helgabalashova marked this conversation as resolved.
Show resolved Hide resolved
attributes: Record<string, string>,
codeDeliveryDetailsList?: CodeDeliveryDetails []
): Record<string, string> {
const attrs = {};
Object.keys(attributes).forEach(key => {
attrs[key] = {
isUpdated: true
};
const codeDeliveryDetails = codeDeliveryDetailsList?.find(value => value.AttributeName === key);
if (codeDeliveryDetails) {
attrs[key].isUpdated = false;
attrs[key].codeDeliveryDetails = codeDeliveryDetails;
helgabalashova marked this conversation as resolved.
Show resolved Hide resolved
}
});
return attrs;
}

/**
* Return user attributes
* @param {Object} user - The CognitoUser object
Expand Down