Repository: parse-community/Parse-SDK-JS
Pull request #860 (2019-07-11 20:04:36)

Add options for AnonymousUtils
This PR also addresses an issue.

```
const user1 = await Parse.User.signUp('anon-not', '1234'); // is current user
const user2 = await Parse.AnonymousUtils.logIn(); // request are made with user1 sessionToken
user2.set('foo', 'bar');
// user2 doesn't have a sessionToken because of https://github.com/parse-community/parse-server/pull/5801
// LinkWith sessionToken won't generate new session token
user2.save();
```

codecov[bot]: # [Codecov](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860?src=pr&el=h1) Report
> Merging [#860](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860?src=pr&el=desc) into [master](https://codecov.io/gh/parse-community/Parse-SDK-JS/commit/93c0538a992a88e76b1e7abbe9109676415fda0a?src=pr&el=desc) will **increase** coverage by `0.02%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860/graphs/tree.svg?width=650&token=8nCENM0QHj&height=150&src=pr)](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #860      +/-   ##
==========================================
+ Coverage   92.09%   92.12%   +0.02%     
==========================================
  Files          54       54              
  Lines        4987     4988       +1     
  Branches     1112     1114       +2     
==========================================
+ Hits         4593     4595       +2     
+ Misses        394      393       -1
```


| [Impacted Files](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/AnonymousUtils.js](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860/diff?src=pr&el=tree#diff-c3JjL0Fub255bW91c1V0aWxzLmpz) | `100% <100%> (ø)` | :arrow_up: |
| [src/ParseUser.js](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860/diff?src=pr&el=tree#diff-c3JjL1BhcnNlVXNlci5qcw==) | `83.18% <100%> (+0.03%)` | :arrow_up: |
| [src/ParseObject.js](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860/diff?src=pr&el=tree#diff-c3JjL1BhcnNlT2JqZWN0Lmpz) | `90.21% <0%> (+0.11%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860?src=pr&el=footer). Last update [93c0538...f4243f4](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/860?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

dplewis: I’m going to write a few test them draft a release 

Patch:
diff --git a/src/AnonymousUtils.js b/src/AnonymousUtils.js
index 801d25b..f1dcedd 100644
--- a/src/AnonymousUtils.js
+++ b/src/AnonymousUtils.js
@@ -10,6 +10,7 @@
  */
 import ParseUser from './ParseUser';
 const uuidv4 = require('uuid/v4');
+import type { RequestOptions } from './RESTController';
 
 let registered = false;
 
@@ -62,12 +63,13 @@ const AnonymousUtils = {
    *
    * @method logIn
    * @name Parse.AnonymousUtils.logIn
+   * @param {Object} options MasterKey / SessionToken.
    * @returns {Promise}
    * @static
    */
-  logIn() {
+  logIn(options?: RequestOptions) {
     const provider = this._getAuthProvider();
-    return ParseUser._logInWith(provider.getAuthType(), provider.getAuthData());
+    return ParseUser._logInWith(provider.getAuthType(), provider.getAuthData(), options);
   },
 
   /**
@@ -76,12 +78,13 @@ const AnonymousUtils = {
    * @method link
    * @name Parse.AnonymousUtils.link
    * @param {Parse.User} user User to link. This must be the current user.
+   * @param {Object} options MasterKey / SessionToken.
    * @returns {Promise}
    * @static
    */
-  link(user: ParseUser) {
+  link(user: ParseUser, options?: RequestOptions) {
     const provider = this._getAuthProvider();
-    return user._linkWith(provider.getAuthType(), provider.getAuthData());
+    return user._linkWith(provider.getAuthType(), provider.getAuthData(), options);
   },
 
   _getAuthProvider() {
diff --git a/src/ParseUser.js b/src/ParseUser.js
index 7f1d03e..f04337a 100644
--- a/src/ParseUser.js
+++ b/src/ParseUser.js
@@ -77,7 +77,8 @@ class ParseUser extends ParseObject {
    * Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can
    * call linkWith on the user (even if it doesn't exist yet on the server).
    */
-  _linkWith(provider: any, options: { authData?: AuthData }, saveOpts?: FullOptions): Promise<ParseUser> {
+  _linkWith(provider: any, options: { authData?: AuthData }, saveOpts?: FullOptions = {}): Promise<ParseUser> {
+    saveOpts.sessionToken = saveOpts.sessionToken || this.getSessionToken() || '';
     let authType;
     if (typeof provider === 'string') {
       authType = provider;
@@ -685,8 +686,8 @@ class ParseUser extends ParseObject {
     return controller.hydrate(userJSON);
   }
 
-  static logInWith(provider: any, options?: RequestOptions) {
-    return ParseUser._logInWith(provider, options);
+  static logInWith(provider: any, options: { authData?: AuthData }, saveOpts?: FullOptions) {
+    return ParseUser._logInWith(provider, options, saveOpts);
   }
 
   /**
@@ -804,9 +805,9 @@ class ParseUser extends ParseObject {
     });
   }
 
-  static _logInWith(provider: any, options?: RequestOptions) {
+  static _logInWith(provider: any, options: { authData?: AuthData }, saveOpts?: FullOptions) {
     const user = new ParseUser();
-    return user._linkWith(provider, options);
+    return user._linkWith(provider, options, saveOpts);
   }
 
   static _clearCache() {


Test patch:
diff --git a/integration/test/ParseUserTest.js b/integration/test/ParseUserTest.js
index 2829ed1..4149622 100644
--- a/integration/test/ParseUserTest.js
+++ b/integration/test/ParseUserTest.js
@@ -536,7 +536,6 @@ describe('Parse User', () => {
     Parse.User.enableUnsafeCurrentUser();
 
     await Parse.User.signUp('foobaz', '1234');
-    await Parse.User.logOut();
 
     const user = await Parse.AnonymousUtils.logIn();
     user.set('field', 'hello world');
@@ -552,6 +551,71 @@ describe('Parse User', () => {
     }
   });
 
+  it('anonymous user logIn does not use currentUser sessionToken', async () => {
+    Parse.User.enableUnsafeCurrentUser();
+
+    const user1 = await Parse.User.signUp('anon-not', '1234');
+    const user2 = await Parse.AnonymousUtils.logIn();
+    expect(user1.getSessionToken()).toBeDefined();
+    expect(user2.getSessionToken()).toBeDefined();
+    expect(user1.getSessionToken()).not.toBe(user2.getSessionToken());
+  });
+
+  it('anonymous user link currentUser', async () => {
+    Parse.User.enableUnsafeCurrentUser();
+
+    const user1 = await Parse.User.signUp('anon-not', '1234');
+    const user2 = await Parse.AnonymousUtils.link(user1);
+    expect(user1.getSessionToken()).toBeDefined();
+    expect(user2.getSessionToken()).toBeDefined();
+    expect(user1.getSessionToken()).toBe(user2.getSessionToken());
+  });
+
+  it('anonymous user link does not use currentUser sessionToken', async () => {
+    Parse.User.enableUnsafeCurrentUser();
+
+    const user1 = await Parse.User.signUp('anon-not', '1234');
+    const user2 = new Parse.User();
+    await Parse.AnonymousUtils.link(user2);
+    expect(user1.getSessionToken()).toBeDefined();
+    expect(user2.getSessionToken()).toBeDefined();
+    expect(user1.getSessionToken()).not.toBe(user2.getSessionToken());
+  });
+
+  it('facebook logIn does not use currentUser sessionToken', async () => {
+    Parse.User.enableUnsafeCurrentUser();
+    Parse.FacebookUtils.init();
+
+    const user1 = await Parse.User.signUp('facebook-not', '1234');
+    const user2 = await Parse.FacebookUtils.logIn();
+    expect(user1.getSessionToken()).toBeDefined();
+    expect(user2.getSessionToken()).toBeDefined();
+    expect(user1.getSessionToken()).not.toBe(user2.getSessionToken());
+  });
+
+  it('facebook link currentUser', async () => {
+    Parse.User.enableUnsafeCurrentUser();
+    Parse.FacebookUtils.init();
+
+    const user1 = await Parse.User.signUp('facebook-not', '1234');
+    const user2 = await Parse.FacebookUtils.link(user1);
+    expect(user1.getSessionToken()).toBeDefined();
+    expect(user2.getSessionToken()).toBeDefined();
+    expect(user1.getSessionToken()).toBe(user2.getSessionToken());
+  });
+
+  it('facebook link does not use currentUser sessionToken', async () => {
+    Parse.User.enableUnsafeCurrentUser();
+    Parse.FacebookUtils.init();
+
+    const user1 = await Parse.User.signUp('facebook-not', '1234');
+    const user2 = new Parse.User();
+    await Parse.FacebookUtils.link(user2);
+    expect(user1.getSessionToken()).toBeDefined();
+    expect(user2.getSessionToken()).toBeDefined();
+    expect(user1.getSessionToken()).not.toBe(user2.getSessionToken());
+  });
+
   it('can signUp user with subclass', async () => {
     Parse.User.enableUnsafeCurrentUser();
 
@@ -649,15 +713,13 @@ describe('Parse User', () => {
     expect(loggedIn.authenticated()).toBeTruthy();
   });
 
-  it('linking un-authenticated user without master key will throw', async (done) => {
+  it('can linking un-authenticated user without master key', async () => {
     const user = new Parse.User();
     user.setUsername('Alice');
     user.setPassword('sekrit');
     await user.save(null, { useMasterKey: true });
-    user._linkWith(provider.getAuthType(), provider.getAuthData())
-      .then(() => done.fail('should fail'))
-      .catch(e => expect(e.message).toBe(`Cannot modify user ${user.id}.`))
-      .then(done);
+    await user._linkWith(provider.getAuthType(), provider.getAuthData());
+    expect(user.getSessionToken()).toBeDefined();
   });
 
   it('can link with custom auth', async () => {
diff --git a/src/__tests__/AnonymousUtils-test.js b/src/__tests__/AnonymousUtils-test.js
index f070555..e287251 100644
--- a/src/__tests__/AnonymousUtils-test.js
+++ b/src/__tests__/AnonymousUtils-test.js
@@ -74,7 +74,7 @@ describe('AnonymousUtils', () => {
     jest.spyOn(user, '_linkWith');
     AnonymousUtils.link(user);
     expect(user._linkWith).toHaveBeenCalledTimes(1);
-    expect(user._linkWith).toHaveBeenCalledWith('anonymous', mockProvider.getAuthData());
+    expect(user._linkWith).toHaveBeenCalledWith('anonymous', mockProvider.getAuthData(), undefined);
     expect(AnonymousUtils._getAuthProvider).toHaveBeenCalledTimes(1);
   });
 
@@ -82,7 +82,7 @@ describe('AnonymousUtils', () => {
     jest.spyOn(MockUser, '_logInWith');
     AnonymousUtils.logIn();
     expect(MockUser._logInWith).toHaveBeenCalledTimes(1);
-    expect(MockUser._logInWith).toHaveBeenCalledWith('anonymous', mockProvider.getAuthData());
+    expect(MockUser._logInWith).toHaveBeenCalledWith('anonymous', mockProvider.getAuthData(), undefined);
     expect(AnonymousUtils._getAuthProvider).toHaveBeenCalledTimes(1);
   });
 });