-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Spike: Running Mounted LB3 App Tests #5251
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
Closed
Closed
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
57187a9
feat(example-lb3-application): add lb3 tests to mocha
nabdelgadir d6329b8
test(example-lb3-application): acceptance tests
nabdelgadir 458e0c2
feat(booter-lb3app): bind lb3 models to context
nabdelgadir 31d552c
test(example-lb3-application): integration tests
nabdelgadir 176651d
style(example-lb3-application): fix linter errors
nabdelgadir 230d4c4
fix: add links to spike
nabdelgadir c6541a8
fixup! fix assertions
nabdelgadir 01e6d3b
fixup! fix failing test
nabdelgadir 0776ac2
fixup! apply feedback
nabdelgadir 81fc3f2
fixup! apply janny feedback
nabdelgadir a823ca8
fixup! more feedback
nabdelgadir File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| # Run LB3 tests from LB4 when LB3 is mounted on the LB4 app | ||
|
|
||
| Since LoopBack 4 offers a way to mount LoopBack 3 applications on a LoopBack 4 | ||
| project with the use of | ||
| [`@loopback/booter-lb3app`](https://github.com/strongloop/loopback-next/tree/master/packages/booter-lb3app), | ||
| there should also be a way for users to run their LoopBack 3 tests as part of | ||
| LoopBack 4's `npm test` command. | ||
|
|
||
| We want the LoopBack 3 tests to use the LoopBack 4 server rather than the | ||
| LoopBack 3 application. This spike aims to test running both acceptance and | ||
| integration LoopBack 3 tests. | ||
|
|
||
| ## All Tests | ||
|
|
||
| In order to run LoopBack 3's tests from their current folder, add LB3 tests' | ||
| path to `test` entry in package.json: | ||
|
|
||
| - `"test": "lb-mocha \"dist/**tests**/\*_/_.js\" \"lb3app/test/\*.js\""` | ||
|
|
||
| In this case, the test folder is | ||
| [`/lb3app/test`](https://github.com/strongloop/loopback-next/tree/spike/lb3test/examples/lb3-application/lb3app/test) | ||
| from the root of the LoopBack 4 project. | ||
|
|
||
| This will run LoopBack 4 tests first then LoopBack 3 tests. | ||
|
|
||
| ## Acceptance Tests | ||
|
|
||
| First, move any LoopBack 3 test dependencies to package.json's devDependencies | ||
| and run: | ||
|
|
||
| ```sh | ||
| npm install | ||
| ``` | ||
|
|
||
| In your test file: | ||
|
|
||
| - Update to use the LB4 Express server when doing requests: | ||
|
|
||
| ```ts | ||
| // can use lb4's testlab's supertest as the dependency is already installed | ||
| const {supertest} = require('@loopback/testlab'); | ||
| const assert = require('assert'); | ||
| const should = require('should'); | ||
| const {ExpressServer} = require('../../dist/server'); | ||
|
|
||
| let app; | ||
|
|
||
| function request(verb, url) { | ||
| // use the LB4 express server | ||
| return supertest(app.server) | ||
| [verb](url) | ||
| .set('Content-Type', 'application/json') | ||
| .set('Accept', 'application/json') | ||
| .expect('Content-Type', /json/); | ||
| } | ||
| ``` | ||
|
|
||
| - Boot and start the LB4 app in your before hook, and stop the app in the after | ||
| hook: | ||
|
|
||
| ```ts | ||
| describe('LoopBack 3 style tests', function () { | ||
| before(async function () { | ||
| app = new ExpressServer(); | ||
| await app.boot(); | ||
| await app.start(); | ||
| }); | ||
|
|
||
| after(async () => { | ||
| await app.stop(); | ||
| }); | ||
|
|
||
| // your tests here | ||
| }); | ||
| ``` | ||
|
|
||
| - Example of this use can be seen in | ||
| [`examples/lb3-application/lb3app/test/acceptance.js`](https://github.com/strongloop/loopback-next/blob/spike/lb3test/examples/lb3-application/lb3app/test/acceptance.js) | ||
| which has the same tests as | ||
| [`src/__tests__/acceptance/lb3app.acceptance.ts`](https://github.com/strongloop/loopback-next/blob/spike/lb3test/examples/lb3-application/src/__tests__/acceptance/lb3app.acceptance.ts), | ||
| but in LB3 style. | ||
|
|
||
| Now when you run `npm test` your LoopBack 3 tests should be run along with any | ||
| LoopBack 4 tests you have. | ||
|
|
||
| Optional: Another option is to migrate your tests to use LoopBack 4 style of | ||
| testing, similar to `src/__tests__/acceptance/lb3app.acceptance.ts`. | ||
| Documentation for LoopBack testing can be found in | ||
| https://loopback.io/doc/en/lb4/Testing-your-application.html. | ||
|
|
||
| ## Integration Tests | ||
|
|
||
| For the integration tests, LoopBack 3 models were bound to the LoopBack 4 | ||
| application in order to allow JavaScript API to call application logic such as | ||
| `Model.create()`. This can be seen in | ||
| [`packages/booter-lb3app/src/lb3app.booter.ts`](https://github.com/strongloop/loopback-next/blob/spike/lb3test/packages/booter-lb3app/src/lb3app.booter.ts#L76-L85). | ||
|
|
||
| In order to retrieve the model from the application's context, `getSync()` can | ||
| be used as follows: | ||
|
|
||
| ```ts | ||
| describe('LoopBack 3 style integration tests', function () { | ||
| let app; | ||
| let CoffeeShop; | ||
|
|
||
| before(async function () { | ||
| app = new ExpressServer(); | ||
| await app.boot(); | ||
| await app.start(); | ||
| }); | ||
|
|
||
| before(() => { | ||
| // follow the syntax: lb3-models.{ModelName} | ||
| CoffeeShop = app.lbApp.getSync('lb3-models.CoffeeShop'); | ||
| }); | ||
|
|
||
| after(async () => { | ||
| await app.stop(); | ||
| }); | ||
|
|
||
| // your tests here | ||
| }); | ||
| ``` | ||
|
|
||
| Alternatively, `get()` can also be used in to retrieve the model asynchronously: | ||
|
|
||
| ```ts | ||
| before(async () => { | ||
| // follow the syntax: lb3-models.{ModelName} | ||
| CoffeeShop = await app.lbApp.get('lb3-models.CoffeeShop'); | ||
| }); | ||
| ``` | ||
|
|
||
| Additionally, LB3 datasources are also bound to the LB4 application's context | ||
| and can be retrieved with a key in the syntax `lb3-datasources.{ds name}`. | ||
|
|
||
| Example integration tests can be found in | ||
| [`examples/lb3-application/lb3app/test/integration.js`](https://github.com/strongloop/loopback-next/blob/spike/lb3test/examples/lb3-application/lb3app/test/integration.js). | ||
|
|
||
| Example authentication tests can be found in | ||
| [`examples/lb3-application/lb3app/test/authentication.js`](https://github.com/strongloop/loopback-next/blob/spike/lb3test/examples/lb3-application/lb3app/test/authentication.js). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| // Copyright IBM Corp. 2020. All Rights Reserved. | ||
| // Node module: @loopback/example-lb3-application | ||
| // This file is licensed under the MIT License. | ||
| // License text available at https://opensource.org/licenses/MIT | ||
|
|
||
| 'use strict'; | ||
| const {supertest} = require('@loopback/testlab'); | ||
| const assert = require('assert'); | ||
| const {ExpressServer} = require('../../dist/server'); | ||
| require('should'); | ||
|
|
||
| let app; | ||
|
|
||
| function request(verb, url) { | ||
| // use the original app's server | ||
| return supertest(app.server) | ||
| [verb](url) | ||
| .set('Content-Type', 'application/json') | ||
| .set('Accept', 'application/json') | ||
| .expect('Content-Type', /json/); | ||
| } | ||
|
|
||
| describe('LoopBack 3 style acceptance tests', function () { | ||
| before(async function () { | ||
| app = new ExpressServer(); | ||
| await app.boot(); | ||
| await app.start(); | ||
| }); | ||
|
|
||
| after(async () => { | ||
| await app.stop(); | ||
| }); | ||
|
|
||
| context('basic REST calls for LoopBack 3 application', () => { | ||
| it('creates and finds a CoffeeShop', function (done) { | ||
| request('post', '/api/CoffeeShops') | ||
| .send({ | ||
| name: 'Coffee Shop', | ||
| city: 'Toronto', | ||
| }) | ||
| .expect(200) | ||
| .end(function (err, res) { | ||
| assert(typeof res.body === 'object'); | ||
| assert(res.body.name); | ||
| assert(res.body.city); | ||
| assert.equal(res.body.name, 'Coffee Shop'); | ||
| assert.equal(res.body.city, 'Toronto'); | ||
| done(); | ||
| }); | ||
| }); | ||
|
|
||
| it("gets the CoffeeShop's status", function (done) { | ||
| request('get', '/api/CoffeeShops/status').expect(200, function ( | ||
| err, | ||
| res, | ||
| ) { | ||
| res.body.status.should.be.equalOneOf( | ||
| 'We are open for business.', | ||
| 'Sorry, we are closed. Open daily from 6am to 8pm.', | ||
| ); | ||
| done(); | ||
| }); | ||
| }); | ||
|
|
||
| it('gets external route in application', function (done) { | ||
| request('get', '/ping').expect(200, function (err, res) { | ||
| assert.equal(res.text, 'pong'); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| // Copyright IBM Corp. 2020. All Rights Reserved. | ||
| // Node module: @loopback/example-lb3-application | ||
| // This file is licensed under the MIT License. | ||
| // License text available at https://opensource.org/licenses/MIT | ||
|
|
||
| 'use strict'; | ||
| const lb3App = require('../server/server'); | ||
| const {supertest} = require('@loopback/testlab'); | ||
| const assert = require('assert'); | ||
| const {ExpressServer} = require('../../dist/server'); | ||
| require('should'); | ||
|
|
||
| let app; | ||
|
|
||
| function request(verb, url) { | ||
| // use the original app's server | ||
| return supertest(app.server) | ||
| [verb](url) | ||
| .set('Content-Type', 'application/json') | ||
| .set('Accept', 'application/json') | ||
| .expect('Content-Type', /json/); | ||
| } | ||
|
|
||
| describe('LoopBack 3 authentication', function () { | ||
| before(async function () { | ||
| app = new ExpressServer(); | ||
| await app.boot(); | ||
| await app.start(); | ||
| }); | ||
|
|
||
| after(async () => { | ||
| await app.stop(); | ||
| }); | ||
|
|
||
| context('authentication', () => { | ||
| let User; | ||
|
|
||
| before(() => { | ||
| User = lb3App.models.User; | ||
| }); | ||
|
|
||
| it('creates a User and logs them in and out', function (done) { | ||
| request('post', '/api/users') | ||
| .send({email: 'new@email.com', password: 'L00pBack!'}) | ||
| .expect(200, function (err, user) { | ||
| assert.equal(user.body.email, 'new@email.com'); | ||
| request('post', '/api/users/login') | ||
| .send({ | ||
| email: 'new@email.com', | ||
| password: 'L00pBack!', | ||
| }) | ||
| .expect(200, function (err2, token) { | ||
| token.body.should.have.properties( | ||
| 'ttl', | ||
| 'userId', | ||
| 'created', | ||
| 'id', | ||
| ); | ||
| assert.equal(token.body.userId, user.body.id); | ||
| request( | ||
| 'post', | ||
| `/api/users/logout?access_token=${token.body.id}`, | ||
| ).expect(204); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| it('rejects anonymous requests to protected endpoints', function (done) { | ||
| request('get', '/api/CoffeeShops/greet').expect(401, function (err, res) { | ||
| assert.equal(res.body.error.code, 'AUTHORIZATION_REQUIRED'); | ||
| }); | ||
| done(); | ||
| }); | ||
|
|
||
| it('makes an authenticated request', function (done) { | ||
| User.create({email: 'new@gmail.com', password: 'L00pBack!'}, function ( | ||
| err, | ||
| user, | ||
| ) { | ||
| user.email.should.be.equal('new@gmail.com'); | ||
| User.login({email: 'new@gmail.com', password: 'L00pBack!'}, function ( | ||
| err2, | ||
| token, | ||
| ) { | ||
| assert.equal(typeof token, 'object'); | ||
| assert.equal(token.userId, user.id); | ||
| request( | ||
| 'get', | ||
| `/api/CoffeeShops/greet?access_token=${token.id}`, | ||
nabdelgadir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ).expect(200, function (err3, res) { | ||
| res.body.greeting.should.be.equal('Hello from this Coffee Shop'); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| // Copyright IBM Corp. 2020. All Rights Reserved. | ||
| // Node module: @loopback/example-lb3-application | ||
| // This file is licensed under the MIT License. | ||
| // License text available at https://opensource.org/licenses/MIT | ||
|
|
||
| 'use strict'; | ||
|
|
||
| const assert = require('assert'); | ||
| const ExpressServer = require('../../dist/server').ExpressServer; | ||
| require('should'); | ||
|
|
||
| describe('LoopBack 3 style integration tests', function () { | ||
| let app; | ||
| let CoffeeShop; | ||
|
|
||
| before(async function () { | ||
| app = new ExpressServer(); | ||
| await app.boot(); | ||
| await app.start(); | ||
| }); | ||
|
|
||
| before(() => { | ||
| CoffeeShop = app.lbApp.getSync('lb3-models.CoffeeShop'); | ||
| }); | ||
|
|
||
| after(async () => { | ||
| await app.stop(); | ||
| }); | ||
|
|
||
| it('CoffeeShop.find', function (done) { | ||
| CoffeeShop.find({where: {name: 'Bel Cafe'}}, function (err, shop) { | ||
| shop[0].__data.name.should.be.equal('Bel Cafe'); | ||
| shop[0].__data.city.should.be.equal('Vancouver'); | ||
| }); | ||
| done(); | ||
| }); | ||
|
|
||
| it('CoffeeShop.count', function (done) { | ||
| CoffeeShop.count({}, function (err, count) { | ||
| assert.equal(count, 5); | ||
| }); | ||
| done(); | ||
| }); | ||
|
|
||
| it('CoffeeShop.create', function (done) { | ||
| CoffeeShop.create( | ||
| { | ||
| name: 'Nook Shop', | ||
| city: 'Toronto', | ||
| }, | ||
| function (err, shop) { | ||
| shop.__data.name.should.be.equal('Nook Shop'); | ||
| shop.__data.city.should.be.equal('Toronto'); | ||
| }, | ||
| ); | ||
| done(); | ||
| }); | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.