Adding tests for mocha and jest

This commit is contained in:
Daniel
2020-04-04 18:03:04 +02:00
parent db0658c785
commit faa910161a
13 changed files with 774 additions and 15 deletions

View File

@@ -4,7 +4,8 @@
"browser": true,
"node": true,
"es6": true,
"jest": true
"jest": true,
"mocha": true
},
"parserOptions": {
"ecmaVersion": 2018

View File

@@ -9,7 +9,9 @@
"esbenp.prettier-vscode",
"mechatroner.rainbow-csv",
"humao.rest-client",
"alexcvzz.vscode-sqlite"
"alexcvzz.vscode-sqlite",
"hbenl.vscode-mocha-test-adapter",
"sdras.night-owl"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [

View File

@@ -2,5 +2,6 @@
"files.exclude": {
"**/.gitignore": true,
"**/.vscode": true
}
},
"cds.checkDevKitInstalled": false
}

15
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "jest",
"group": {
"kind": "test",
"isDefault": true
}
}
]
}

View File

@@ -37,6 +37,14 @@ cds watch bookshop
After that open this link in your browser: [http://localhost:4004](http://localhost:4004)
### Testing
Run the provided tests with [_jest_](http://jestjs.io) or [_mocha_](http://mochajs.org), e.g.:
```sh
npx jest
```
> While mocha is a bit smaller and faster, jest runs tests in parallel and isolation which allows to run all tests.
## Get Support

View File

@@ -1,3 +1,4 @@
namespace sap.capire.bookshop; //> important for reflection
using from './db/schema';
using from './srv/cat-service';
using from './srv/admin-service';

View File

@@ -8,15 +8,20 @@
"@capire/bookshop": "file:bookshop",
"@capire/common": "file:common",
"@capire/fiori": "file:fiori",
"@capire/media": "file:media",
"@capire/orders": "file:orders",
"@capire/reviews": "file:reviews"
"@capire/reviews": "file:reviews",
"@capire/tests": "file:test"
},
"devDependencies": {
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"chai-subset": "^1.6.0",
"sqlite3": "^4"
},
"scripts": {
"mocha": "npx mocha || echo",
"jest": "npx jest"
},
"license": "SAP SAMPLE CODE LICENSE",
"private": true
}

95
test/bookshop.test.js Normal file
View File

@@ -0,0 +1,95 @@
describe('@capire/bookshop', () => {
const { GET, POST, expect } = require('@capire/tests') .launch ('@capire/bookshop')
it ('should serve $metadata documents in v4', async () => {
const {headers,status,data} = await GET `/browse/$metadata`
expect (headers) .to.contain ({
"content-type": 'application/xml',
"odata-version": "4.0",
})
expect (data) .to.contain (
'<EntitySet Name="Books" EntityType="CatalogService.Books">',
)
expect (data) .to.contain (
'<Annotation Term="Common.Label" String="Currency"/>'
)
expect (status) .to.equal (200)
})
it ('should serve localized $metadata documents', async () => {
const {data} = await GET `/browse/$metadata?sap-language=de`
expect (data) .to.contain (
'<Annotation Term="Common.Label" String="Währung"/>'
)
})
it ('should serve localized Books with $expanded currency', async () => {
const {data} = await GET `/browse/Books?&$select=title,author&$expand=currency&sap-language=de`
expect (data.value) .to.containSubset ([
{
ID:201, title: 'Sturmhöhe', author: 'Emily Brontë', currency: {
code: 'GBP',
descr: 'Britische Pfund',
name: 'Pfund',
symbol: '£'
}
},
{
ID:207, title: 'Jane Eyre', author: 'Charlotte Brontë', currency: {
descr: 'Britische Pfund',
}
},
{
ID:251, title: 'The Raven', author: 'Edgar Allen Poe', currency: {
code: 'USD',
name: 'US-Dollar',
symbol: '$'
}
},
{
ID:252, title: 'Eleonora', author: 'Edgar Allen Poe'
},
{
ID:271, title: 'Catweazle', author: 'Richard Carpenter', currency: {
code: 'EUR',
name: 'Euro',
symbol: '€'
}
}
])
})
it ('should serve localized Authors w/ $expanded book and currency', async () => {
const {data} = await GET (`/admin/Authors/101?sap-language=de`
+ `&$expand=books($select=title;$expand=currency($select=code,name,symbol))`
+ `&$select=name`)
expect (data) .to.eql ({
'@odata.context': '$metadata#Authors(name,ID,books(title,ID,currency(code,name,symbol)))/$entity',
ID:101, name: 'Emily Brontë', books: [
{ ID:201, title: 'Sturmhöhe', currency: {
code:'GBP', name: 'Pfund', symbol: '£'
}}
],
})
})
it ('should check on current stocks with $value', async () => {
const { data } = await GET `/admin/Books/201/stock/$value`
expect(data) .to.equal (12)
})
it ('should reject out-of-stock orders', ()=> {
return expect (Promise.all ([
POST ('/browse/submitOrder', { book: 201, amount: 5 }),
POST ('/browse/submitOrder', { book: 201, amount: 5 }),
POST ('/browse/submitOrder', { book: 201, amount: 5 }),
])) .to.be.rejectedWith (/409 - 5 exceeds stock for book #201/)
})
})

531
test/cds.ql.test.js Normal file
View File

@@ -0,0 +1,531 @@
const { expect } = require('@capire/tests')
const cds = require('@sap/cds')
const CQL = ([cql]) => cds.parse.cql(cql)
const Foo = { name: 'Foo' }
const Books = { name: 'capire.bookshop.Books' }
const is_cds_333 = cds.version >= '3.33.3'
if (!is_cds_333) {
// Monky-patching v3.33.3 features in older releases
const up = UPDATE('x').constructor.prototype
up.with = up.set
}
// while jest has 'test' as alias to 'it', mocha doesn't
if (!global.test) global.test = it
describe('cds.ql', () => {
//
describe(`BUGS + GAPS...`, () => {
it.skip('should consistently handle *', () => {
expect({
SELECT: { from: { ref: ['Foo'] }, columns: ['*'] },
})
.to.eql(CQL`SELECT * from Foo`)
.to.eql(CQL`SELECT from Foo{*}`)
.to.eql(SELECT('*').from(Foo))
.to.eql(SELECT.from(Foo, ['*']))
})
it.skip('should correctly handle { ... and:{...} }', () => {
expect(SELECT.from(Foo).where({ x: 1, and: { y: 2, or: { z: 2 } } })).to.eql({
SELECT: {
from: { ref: ['Foo'] },
where: [
{ ref: ['x'] },
'=',
{ val: 1 },
'and',
'(',
{ ref: ['y'] },
'=',
{ val: 2 },
'or',
{ ref: ['z'] },
'=',
{ val: 3 },
')',
],
},
})
})
})
describe(`SELECT...`, () => {
test('from ( Foo )', () => {
expect({
SELECT: { from: { ref: ['Foo'] } },
})
.to.eql(CQL`SELECT from Foo`)
.to.eql(SELECT.from(Foo))
})
test('from ( ..., <key>)', () => {
// Compiler
expect(CQL`SELECT from Foo[11]`).to.eql({
SELECT: {
// REVISIT: add one:true?
from: { ref: [{ id: 'Foo', where: [{ val: 11 }] }] },
},
})
expect(CQL`SELECT from Foo[ID=11]`).to.eql({
SELECT: {
// REVISIT: add one:true
from: {
ref: [{ id: 'Foo', where: [{ ref: ['ID'] }, '=', { val: 11 }] }],
},
},
})
// Runtime ds.ql
expect(SELECT.from(Foo, 11))
.to.eql(SELECT.from(Foo, { ID: 11 }))
.to.eql(SELECT.from(Foo).byKey(11))
.to.eql(SELECT.from(Foo).byKey({ ID: 11 }))
.to.eql(SELECT.one.from(Foo).where({ ID: 11 }))
.to.eql({
// REVISIT: should produce CQN as the ones above?
SELECT: {
one: true,
from: { ref: ['Foo'] },
where: [{ ref: ['ID'] }, '=', { val: 11 }],
},
})
expect(CQL`SELECT from Foo[11]{a}`).to.eql({
SELECT: {
// REVISIT: add one:true?
from: { ref: [{ id: 'Foo', where: [{ val: 11 }] }] },
columns: [{ ref: ['a'] }],
},
})
expect(SELECT.from(Foo, 11, ['a']))
.to.eql(SELECT.from(Foo, 11, (foo) => foo.a))
.to.eql({
// REVISIT: should produce CQN as the ones above?
SELECT: {
one: true,
from: { ref: ['Foo'] },
columns: [{ ref: ['a'] }],
where: [{ ref: ['ID'] }, '=', { val: 11 }],
},
})
})
test('from ( ..., => {...})', () => {
// single *, prefix and postfix, as array and function
expect(CQL`SELECT * from Foo`).to.eql(CQL`SELECT from Foo{*}`)
//> .to.eql... FIXME: see skipped 'should handle * correctly' below
expect(SELECT('*').from(Foo))
.to.eql(SELECT.from(Foo, ['*']))
.to.eql(SELECT.from(Foo, (foo) => foo('*')))
.to.eql(SELECT.from(Foo).columns('*'))
.to.eql(SELECT.from(Foo).columns((foo) => foo('*')))
.to.eql({
SELECT: { from: { ref: ['Foo'] }, columns: [{ ref: ['*'] }] },
})
// single column, prefix and postfix, as array and function
expect(CQL`SELECT a from Foo`)
expect(CQL`SELECT from Foo {a}`)
.to.eql(SELECT.from(Foo, ['a']))
.to.eql(SELECT.from(Foo, (foo) => foo.a))
.to.eql({
SELECT: { from: { ref: ['Foo'] }, columns: [{ ref: ['a'] }] },
})
// multiple columns, prefix and postfix, as array and function
expect(CQL`SELECT a,b as c from Foo`)
expect(CQL`SELECT from Foo {a,b as c}`)
.to.eql(SELECT.from(Foo, ['a', { b: 'c' }]))
.to.eql(
SELECT.from(Foo, (foo) => {
foo.a, foo.b.as('c')
})
)
.to.eql(SELECT.from(Foo).columns('a', { b: 'c' }))
.to.eql(SELECT.from(Foo).columns(['a', { b: 'c' }]))
.to.eql(
SELECT.from(Foo).columns((foo) => {
foo.a, foo.b.as('c')
})
)
.to.eql({
SELECT: {
from: { ref: ['Foo'] },
columns: [{ ref: ['a'] }, { ref: ['b'], as: 'c' }],
},
})
// multiple columns and *, prefix and postfix, as array and function
expect(CQL`SELECT *,a,b from Foo`).to.eql(CQL`SELECT from Foo{*,a,b}`)
//> .to.eql... FIXME: see skipped 'should handle * correctly' below
expect(SELECT.from(Foo, ['a', 'b', '*']))
.to.eql(SELECT.from(Foo).columns('a', 'b', '*'))
.to.eql(SELECT.from(Foo).columns(['a', 'b', '*']))
.to.eql(
SELECT.from(Foo, (foo) => {
foo.a, foo.b, foo('*')
})
)
.to.eql({
SELECT: {
from: { ref: ['Foo'] },
columns: [{ ref: ['a'] }, { ref: ['b'] }, { ref: ['*'] }],
},
})
})
is_cds_333 &&
test('from ( ..., => _.expand ( x=>{...}))', () => {
// SELECT from Foo { *, x, bar.*, car{*}, boo { *, moo.zoo } }
expect(
SELECT.from(Foo, (foo) => {
foo('*'),
foo.x,
foo.car('*'),
foo.boo((b) => {
b('*'), b.moo.zoo((x) => x.y.z)
})
})
).to.eql({
SELECT: {
from: { ref: ['Foo'] },
columns: [
{ ref: ['*'] },
{ ref: ['x'] },
{ ref: ['car'], expand: ['*'] },
{
ref: ['boo'],
expand: ['*', { ref: ['moo', 'zoo'], expand: [{ ref: ['y', 'z'] }] }],
},
],
},
})
})
is_cds_333 &&
test('from ( ..., => _.inline ( _=>{...}))', () => {
// SELECT from Foo { *, x, bar.*, car{*}, boo { *, moo.zoo } }
expect(
SELECT.from(Foo, (foo) => {
foo.bar('*'),
foo.bar('.*'), //> leading dot indicates inline
foo.boo((x) => x.moo.zoo),
foo.boo((_) => _.moo.zoo) //> underscore arg name indicates inline
})
).to.eql({
SELECT: {
from: { ref: ['Foo'] },
columns: [
{ ref: ['bar'], expand: ['*'] },
{ ref: ['bar'], inline: ['*'] },
{ ref: ['boo'], expand: [{ ref: ['moo', 'zoo'] }] },
{ ref: ['boo'], inline: [{ ref: ['moo', 'zoo'] }] },
],
},
})
})
test('one / distinct ...', () => {
expect(SELECT.distinct.from(Foo).cqn)
// .to.eql(CQL(`SELECT distinct from Foo`).SELECT)
.to.eql(SELECT.distinct(Foo).cqn)
.to.eql({ distinct: true, from: { ref: ['Foo'] } })
expect(SELECT.one.from(Foo).cqn)
// .to.eql(CQL(`SELECT one from Foo`).SELECT)
.to.eql(SELECT.one(Foo).cqn)
.to.eql({ one: true, from: { ref: ['Foo'] } })
expect(SELECT.one('a').from(Foo).cqn)
// .to.eql(CQL(`SELECT distinct a from Foo`).SELECT)
.to.eql(SELECT.one(['a']).from(Foo).cqn)
.to.eql(SELECT.one(Foo, ['a']).cqn)
.to.eql(SELECT.one(Foo, (foo) => foo.a).cqn)
.to.eql(SELECT.one.from(Foo, (foo) => foo.a).cqn)
.to.eql(SELECT.one.from(Foo, ['a']).cqn)
.to.eql({
one: true,
from: { ref: ['Foo'] },
columns: [{ ref: ['a'] }],
})
// same for works distinct
})
test('where ( ... cql | {x:y} )', () => {
const args = [`foo`, "'bar'", 3]
const ID = 11
// using simple predicate objects
// (Note: this doesn't support paths in left-hand-sides, nor references in arrays)
expect(
SELECT.from(Foo).where({
ID,
args,
and: { x: { like: '%x%' }, or: { y: { '>=': 9 } } },
})
).to.eql({
SELECT: {
from: { ref: ['Foo'] },
where: [
'(', //> this one is not required
{ ref: ['ID'] },
'=',
{ val: ID },
'and',
{ ref: ['args'] },
'in',
{ val: args },
'and',
// '(', //> this one is missing, and that's changing the logic -> that's a BUG
{ ref: ['x'] },
'like',
{ val: '%x%' },
'or',
{ ref: ['y'] },
'>=',
{ val: 9 },
')',
],
},
})
// using CQL fragments -> uses cds.parse.expr
expect(CQL`SELECT from Foo where ID=11 and x in ( foo, 'bar', 3)`)
.to.eql(SELECT.from(Foo).where(`ID=`, ID, `and x in`, args))
.to.eql(SELECT.from(Foo).where(`ID=${ID} and x in (${args})`))
.to.eql({
SELECT: {
from: { ref: ['Foo'] },
where: [
{ ref: ['ID'] },
'=',
{ val: ID },
'and',
{ ref: ['x'] },
'in',
'(',
{ ref: ['foo'] },
',',
{ val: 'bar' },
',',
{ val: 3 },
')',
],
},
})
expect(CQL`SELECT from Foo where x=1 or y.z is null and (a>2 or b=3)`).to.eql(
SELECT.from(Foo).where(`x=`, 1, `or y.z is null and (a>`, 2, `or b=`, 3, `)`)
)
expect(CQL`SELECT from Foo where x between 1 and 9`).to.eql(
SELECT.from(Foo).where(`x between`, 1, `and`, 9)
)
})
test('w/ sub selects', () => {
// in where causes
expect(CQL`SELECT from Foo where x in (SELECT y from Bar)`).to.eql(
SELECT.from(Foo).where({ x: SELECT('y').from('Bar') })
)
// in classical semi joins
expect(CQL`SELECT x from Foo where exists (SELECT 1 from Bar where y=x)`).to.eql(
SELECT('x').from(Foo) .where ( `exists`,
SELECT(1).from('Bar') .where ({ y: { ref: ['x'] } })
) // prettier-ignore
)
// in select clauses
cds.version >= '3.33.3' &&
expect(CQL`SELECT from Foo { x, (SELECT y from Bar) as y }`)
.to.eql(
SELECT.from(Foo, (foo) => {
foo.x, foo(SELECT.from('Bar', (b) => b.y)).as('y')
})
)
.to.eql(
SELECT.from(Foo, ['x', Object.assign(SELECT('y').from('Bar'), { as: 'y' })])
)
})
it('w/ plain SQL', () => {
expect(SELECT.from(Books) + 'WHERE ...').to.eql(
'SELECT * FROM capire_bookshop_Books WHERE ...'
)
})
//
})
describe(`INSERT...`, () => {
test('entries ({a,b}, ...)', () => {
const entries = [{ foo: 1 }, { boo: 2 }]
expect(INSERT(...entries).into(Foo))
.to.eql(INSERT(entries).into(Foo))
.to.eql(INSERT.into(Foo).entries(...entries))
.to.eql(INSERT.into(Foo).entries(entries))
.to.eql({
INSERT: { into: 'Foo', entries },
})
})
test('rows ([1,2], ...)', () => {
expect(
INSERT.into(Foo)
.columns('a', 'b')
.rows([
[1, 2],
[3, 4],
])
)
.to.eql(INSERT.into(Foo).columns('a', 'b').rows([1, 2], [3, 4]))
.to.eql({
INSERT: {
into: 'Foo',
columns: ['a', 'b'],
rows: [
[1, 2],
[3, 4],
],
},
})
})
test('values (1,2)', () => {
expect(INSERT.into(Foo).columns('a', 'b').values([1, 2]))
.to.eql(INSERT.into(Foo).columns('a', 'b').values(1, 2))
.to.eql({
INSERT: { into: 'Foo', columns: ['a', 'b'], values: [1, 2] },
})
})
test('w/ plain SQL', () => {
expect(INSERT.into(Books) + 'VALUES ...').to.eql(
'INSERT INTO capire_bookshop_Books VALUES ...'
)
})
})
describe(`UPDATE...`, () => {
test('entity (..., <key>)', () => {
expect(UPDATE(Books, 4711))
.to.eql(UPDATE(Books, { ID: 4711 }))
.to.eql(UPDATE(Books).byKey(4711))
.to.eql(UPDATE(Books).byKey({ ID: 4711 }))
.to.eql(UPDATE(Books).where({ ID: 4711 }))
.to.eql(UPDATE(Books).where(`ID=`, 4711))
.to.eql(UPDATE.entity(Books, 4711))
.to.eql(UPDATE.entity(Books, { ID: 4711 }))
// etc...
.to.eql({
UPDATE: {
entity: 'capire.bookshop.Books',
where: [{ ref: ['ID'] }, '=', { val: 4711 }],
},
})
})
/*
UPDATE.with allows to pass in plain data payloads, e.g. as obtained from REST clients.
In addition, UPDATE.with supports specifying expressions, either in CQL fragements
notation or as simple expression objects.
*/
test('with', () => {
expect(UPDATE(Foo).with(`foo=11, bar = bar - 22`))
.to.eql(UPDATE(Foo).with(`foo=`, 11, `bar-=`, 22))
.to.eql(UPDATE(Foo).with({ foo: 11, bar: { '-=': 22 } }))
.to.eql({
UPDATE: {
entity: 'Foo',
with: {
foo: { val: 11 },
bar: { xpr: [{ ref: ['bar'] }, '-', { val: 22 }] },
},
},
})
// some more
expect(UPDATE(Foo).with(`bar = coalesce(x,y), car = 'foo''s bar, car'`)).to.eql({
UPDATE: {
entity: 'Foo',
with: {
bar: { func: 'coalesce', args: [{ ref: ['x'] }, { ref: ['y'] }] },
car: { val: "foo's bar, car" },
},
},
})
})
/*
UPDATE.data allows to pass in plain data payloads, e.g. as obtained from REST clients.
The passed in object can be modified subsequently, e.g. by adding or modifying values
before the query is finally executed.
*/
test('data', () => {
const o = {}
const q = UPDATE(Foo).data(o).with(`bar-=`, 22)
o.foo = 11
expect(q).to.eql({
UPDATE: {
entity: 'Foo',
data: { foo: 11 },
with: {
bar: { xpr: [{ ref: ['bar'] }, '-', { val: 22 }] },
},
},
})
})
test('w/ plain SQL', () => {
expect(UPDATE(Books) + 'SET ...').to.eql('UPDATE capire_bookshop_Books SET ...')
})
})
describe(`DELETE...`, () => {
test('from (..., <key>)', () => {
expect(DELETE(Books, 4711))
.to.eql(DELETE(Books, { ID: 4711 }))
.to.eql(DELETE.from(Books, 4711))
.to.eql(DELETE.from(Books, { ID: 4711 }))
.to.eql(DELETE.from(Books).byKey(4711))
.to.eql(DELETE.from(Books).byKey({ ID: 4711 }))
.to.eql(DELETE.from(Books).where({ ID: 4711 }))
.to.eql(DELETE.from(Books).where(`ID=`, 4711))
.to.eql({
DELETE: {
from: 'capire.bookshop.Books',
where: [{ ref: ['ID'] }, '=', { val: 4711 }],
},
})
})
test('/w plain SQL', () => {
expect(DELETE.from(Books) + 'WHERE ...').to.eql(
'DELETE FROM capire_bookshop_Books WHERE ...'
)
})
})
describe(`cds.ql etc...`, () => {
it('queries marked for cds repl', () => {
expect(UPDATE(Foo)._isQuery).to.be.true
})
it('should keep null and undefined', () => {
for (let each of [null, undefined]) {
expect(SELECT.from(Foo).where({ ID: each })).to.eql({
SELECT: {
from: { ref: ['Foo'] },
where: [{ ref: ['ID'] }, '=', { val: each }],
},
})
}
})
})
//
})

View File

@@ -1,10 +1,10 @@
const {expect} = require('@capire/tests')
const cds = require ('@sap/cds')
const {expect} = cds.require.chai
describe('reading/writing hierarchies', ()=>{
describe('Hierarchical CodeLists', ()=>{
it ('should bootstrap sqlite in-memory db', async()=>{
await cds.deploy (__dirname+'/../db') .to ('sqlite::memory:')
it ('should bootstrap sqlite in-memory db...', async()=>{
await cds.deploy ('@capire/bookshop') .to ('sqlite::memory:')
expect (cds.db) .to.exist
expect (cds.db.model) .to.exist
})
@@ -20,7 +20,7 @@ describe('reading/writing hierarchies', ()=>{
{ ID:105, name:'Kitty Bat' } ]},
{ ID:106, name:'Catwoman', children:[
{ ID:107, name:'Catalina' } ]} ]},
{ ID:108, name:'Catweazle' }
{ ID:108, name:'Ca<tweazle' }
]}
)
})
@@ -45,7 +45,7 @@ describe('reading/writing hierarchies', ()=>{
)
})
it ('should read hierarchy of genres', async()=>{
it ('should read deep hierarchy of genres', async()=>{
const { Genres } = cds.entities
expect (await

94
test/lib/helpers.js Normal file
View File

@@ -0,0 +1,94 @@
/** For static usage w/o launching a server */
module.exports = exports = {
get chai() { return _chai() },
get expect(){ return this.chai.expect },
get assert(){ return this.chai.assert },
}
// harmonizing jest and mocha
if (global.test) { // it's jest
global.before = global.beforeAll
global.after = global.afterAll
} else { // it's mocha
global.beforeAll = global.before
global.afterAll = global.after
}
// lazy-loading chai
function _chai(){
const chai = exports.chai = require('chai')
.use (require('chai-as-promised'))
.use (require('chai-subset'))
chai.should()
return chai
}
/** Launching and testing a cds server */
exports.launch = (project, args=['--in-memory?']) => {
const cds = require('@sap/cds')
if (!cds.utils.existsSync(project)) try {
project = require('path').dirname (require.resolve(project+'/package.json'))
} catch(e) {
throw cds.error (`Cannot resolve project folder for '${project}'`)
}
const axios = require('axios').default
let baseURL //... be filled in below
// launch cds server...
before (done => {
const console = global.console, logs=[]
global.console = { __proto__: global.console, logs,
time: ()=>{}, timeEnd: (...args)=> logs.push(args),
debug: (...args)=> logs.push(args),
log: (...args)=> logs.push(args),
warn: (...args)=> logs.push(args),
error: (...args)=> logs.push(args),
dump(){ for (let each of logs) console.log (...each) },
}
process.env.PORT = '0'
const p = cds.exec ('run', project, ...args) // TODO w/ @sap/cds@3.33.3: , '--port', '0')
if (p && 'catch' in p) p.catch (done)
cds.once('listening', ({ server, url }) => {
after (done => {
if (global.console !== console) global.console = console
server.close (done)
})
baseURL = url
done()
})
})
return {
GET: (path) => axios.get (baseURL+path) .catch(_error),
PUT: (path,data) => axios.put (baseURL+path,data) .catch(_error),
POST: (path,data) => axios.post (baseURL+path,data) .catch(_error),
PATCH: (path,data) => axios.patch (baseURL+path,data) .catch(_error),
DELETE: (path) => axios.delete (baseURL+path) .catch(_error),
get: (path) => axios.get (baseURL+path) .catch(_error),
put: (path,data) => axios.put (baseURL+path,data) .catch(_error),
post: (path,data) => axios.post (baseURL+path,data) .catch(_error),
patch: (path,data) => axios.patch (baseURL+path,data) .catch(_error),
delete: (path) => axios.delete (baseURL+path) .catch(_error),
get chai(){ return _chai() },
get expect(){ return this.chai.expect },
get assert(){ return this.chai.assert },
}
function _error (e) {
if (!e.response) throw e
if (!e.response.data) throw e
if (!e.response.data.error) throw e
const { code, message } = e.response.data.error
throw new Error (`${code} - ${message}`)
}
}

View File

@@ -1,8 +1,9 @@
const _model = __dirname+'/..'
const {expect} = require('@capire/tests')
const cds = require ('@sap/cds')
const {expect} = cds.require.chai
const _model = '@capire/reviews'
describe('messaging tests', ()=>{
describe('Messaging', ()=>{
it ('should bootstrap sqlite in-memory db', async()=>{
const db = await cds.deploy (_model) .to ('sqlite::memory:')
@@ -10,7 +11,7 @@ describe('messaging tests', ()=>{
})
let srv
it ('should serve reviews services', async()=>{
it ('should serve ReviewsService', async()=>{
srv = await cds.serve('ReviewsService') .from (_model)
expect (srv.name) .to.match (/ReviewsService/)
})

5
test/package.json Normal file
View File

@@ -0,0 +1,5 @@
{
"name": "@capire/tests",
"version": "1.0.0",
"main": "lib/helpers.js"
}