markdown 挑战20测试JWT

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown 挑战20测试JWT相关的知识,希望对你有一定的参考价值。

# Challenge - Testing JWTs and Protected Endpoints

In this challenge you will update integration tests to support to test JWT authorization. You can use the [Node JWT Auth](https://github.com/Thinkful-Ed/node-jwt-auth) as a guide.

## Access Protected Endpoint

Chia-Http makes accessing endpoints protected by JWTs is relatively easy. Simply create a valid JWT using the site's `JWT_SECRET` and add it as a Bearer token to each request. But there's a wrinkle, the resources (eg. notes, folders and tags) belong to an specifec individual so the JWT must be created using the seed data. And the tests must be updated to check for the specific user's resources.

We'll tackle this challenge in 2 steps. First, configure the tests to generate a valid JWT and use it to test an endpoint. Second, update the tests to verify the data based on the user.

### Create a JWT in `beforeEach`

Starting with `/test/folders.test.js` update the `beforeEach` as follows.

Loop to map over the `seedUser` to hash the passwords. At first, the map contains an array of pending promises which you can pass to `Promise.all()`. When all the promises resolved, then loop over the results and update passwords in `seedData` with the digests. Now you are ready to insert the users along with the folders. Finally, when all the data has been inserted, capture the users and extract the first user and create a valid JWT.

```js
  // Define a token and user so it is accessible in the tests
  let token; 
  let user;

  beforeEach(function () {
    return Promise.all(seedUsers.map(user => User.hashPassword(user.password)))
      .then(digests => {
        seedUsers.forEach((user, i) => user.password = digests[i]);
        return Promise.all([
          User.insertMany(seedUsers),
          Folder.insertMany(seedFolders),
          Folder.createIndexes()
        ]);
      })
      .then(([users]) => {
        user = users[0];
        token = jwt.sign({ user }, JWT_SECRET, { subject: user.username });
      });
  });
```

### Add JWT to request header

Before attempting to add the JWT to your requests you should update your test suite so only one test is executed. This allows you to focus on one test at a time. In the example below we are focusing on the `GET /api/folders`. Add `.only` or `.skip` to the `describe` and it `blocks` as needed.

Now we need to add the JWT to the `Authorization` header as a Bearer token. Luckily, the Chai-HTTP `.set()` method makes this easy. Below is a generic example

```js
  chai.request(app)
    .get('/api/protected')
    .set('Authorization', `Bearer ${token}`)
    .then(() => {
      /*...*/
    });
```

Add the Authorization header with the Bearer token to the `/api/folders/` test as shown below.

```js
  describe.only('GET /api/folders', function () {
    it('should return the correct number of folders', function () {
      const dbPromise = Folder.find();
      const apiPromise = chai.request(app)
        .get('/api/folders')
        .set('Authorization', `Bearer ${token}`); // <<== Add this

      return Promise.all([dbPromise, apiPromise])
        .then(([data, res]) => {
          expect(res).to.have.status(200);
          expect(res).to.be.json;
          expect(res.body).to.be.a('array');
          expect(res.body).to.have.length(data.length);
        });
    });
```

Now when you run the test, you should no longer get an Unauthorized error, but the test will not pass. Comment-out the `expect(res.body).to.have.length(data.length)` assertion and run it again.

Let's fix the length issue now.

### Update tests to expect specific user content

The test did not pass because the `/api/folders/` endpoint returns results for a specific user. But the database cross-check is still selecting **all** folders. You need to update the `Folder.find()` to include the User id like so:

```js
  Folder.find({ userId: user.id })
```

The complete test will look like this:

```js
  it('should return the correct number of folders', function () {
    const dbPromise = Folder.find({ userId: user.id });
    const apiPromise = chai.request(app)
      .get('/api/folders')
      .set('Authorization', `Bearer ${token}`);

    return Promise.all([dbPromise, apiPromise])
      .then(([data, res]) => {
        expect(res).to.have.status(200);
        expect(res).to.be.json;
        expect(res.body).to.be.a('array');
        expect(res.body).to.have.length(data.length);
      });
  });
```

Let's try another one. The next test verifies that the response contains the correct keys. The updated endpoint now returns the `userId` in addition to the `id` and `name`. Update your test with the Authorization header, add a filter to the database query and update the assertion as shown below.

```js
  it('should return a list with the correct right fields', function () {
    const dbPromise = Folder.find({ userId: user.id }); // <<== Add filter on User Id
    const apiPromise = chai.request(app)
      .get('/api/folders')
      .set('Authorization', `Bearer ${token}`); // <<== Add Authorization header

    return Promise.all([dbPromise, apiPromise])
      .then(([data, res]) => {
        expect(res).to.have.status(200);
        expect(res).to.be.json;
        expect(res.body).to.be.a('array');
        res.body.forEach(function (item) {
          expect(item).to.be.a('object');
          expect(item).to.have.keys('id', 'name', 'userId', 'createdAt', 'updatedAt');  // <<== Update assertion
        });
      });
  });
```

Your challenge!

Update the rest of the Folder tests **and** then apply your learning to the Tag and Note tests.

## Deploy the app

If time allows, you should push your changes to GitHub and verify your tests pass on Travis CI and are deployed to Heroku.

以上是关于markdown 挑战20测试JWT的主要内容,如果未能解决你的问题,请参考以下文章

markdown 挑战10:Knex JS测试

markdown 挑战:19.1测试本地身份验证

markdown 挑战19:测试Auth

markdown 挑战13:猫鼬测试

markdown 挑战05:使用摩卡柴进行测试

如何访问自定义 Ktor JWT 挑战中的错误?