Compare commits
1 Commits
addCustomR
...
using-upse
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3965ac697 |
@@ -1,15 +0,0 @@
|
||||
const cds = require("@sap/eslint-plugin-cds");
|
||||
|
||||
module.exports = {
|
||||
configs: {
|
||||
recommended: {
|
||||
plugins: ["cloud-cap-samples"],
|
||||
rules: {
|
||||
"cloud-cap-samples/no-open-services": ["error", "show"]
|
||||
}
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
"no-open-services": cds.createRule(require("./rules/no-open-services")),
|
||||
}
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "eslint-plugin-cloud-cap-samples",
|
||||
"description": "Contains shareable custom lint rules for this repository",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: "Service without `@requires/restrict` should not expose fields with personal data.",
|
||||
version: "1.0.0"
|
||||
},
|
||||
fixable: "code",
|
||||
model: "inferred"
|
||||
},
|
||||
create: function (context) {
|
||||
const services = context.getModel() ? context.getModel().services : [];
|
||||
const unprotectedServices = services.filter(s => !s["@requires"] && !s["@restrict"]).map(s => s.name)
|
||||
return { entity: checkForExposedFields };
|
||||
|
||||
function checkForExposedFields(entity) {
|
||||
const entityInUnprotectedService = unprotectedServices.some(service => entity.name.includes(service))
|
||||
if (entityInUnprotectedService) {
|
||||
const elements = Object.keys(entity.elements).filter((name) => ["createdBy", "modifiedBy"].includes(name))
|
||||
for (let element of elements) {
|
||||
context.report({
|
||||
message: `Field '${element}' in '${entity.name}' exposes personal data. Remove field or add \`@restrict/requires\`.`,
|
||||
node: context.getNode(entity),
|
||||
file: entity.$location.file
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
{
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@sap/cds/recommended",
|
||||
"plugin:cloud-cap-samples/recommended"
|
||||
],
|
||||
"plugins": [
|
||||
"cloud-cap-samples"
|
||||
"plugin:@sap/cds/recommended"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
@@ -27,7 +23,7 @@
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"require-atomic-updates": "off",
|
||||
"require-await": "warn",
|
||||
"require-await":"warn",
|
||||
"no-unused-vars": ["warn", { "argsIgnorePattern": "_" }]
|
||||
}
|
||||
}
|
||||
|
||||
1
.registry/.gitignore
vendored
Normal file
1
.registry/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.tgz
|
||||
81
.registry/server.js
Normal file
81
.registry/server.js
Normal file
@@ -0,0 +1,81 @@
|
||||
const { exec } = require ('child_process')
|
||||
const isWin = process.platform === 'win32'
|
||||
const express = require ('express')
|
||||
const fs = require ('fs')
|
||||
const app = express()
|
||||
|
||||
const { PORT=4444 } = process.env
|
||||
const [,,port=PORT,scope='@capire'] = process.argv
|
||||
const cwd = __dirname
|
||||
|
||||
// clean up on start (exit handler might not complete on Windows)
|
||||
exec(isWin ? 'del *.tgz' : 'rm *.tgz', {cwd})
|
||||
|
||||
|
||||
app.use('/-/:tarball', (req,res,next) => {
|
||||
console.debug ('GET', req.params)
|
||||
try {
|
||||
const { tarball } = req.params
|
||||
const pkgFull = tarball.substring(0, tarball.lastIndexOf('-'))
|
||||
const [, pkg ] = /^\w+-(.+)/.exec(pkgFull)
|
||||
fs.lstat(tarball,(err => {
|
||||
if (err) console.debug (`npm pack ../${pkg}`)
|
||||
if (err) exec(`npm pack ../${pkg}`,{cwd},next)
|
||||
else next()
|
||||
}))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
res.sendStatus(500)
|
||||
}
|
||||
})
|
||||
|
||||
app.use('/-', express.static(__dirname))
|
||||
|
||||
app.get('/*', (req,res)=>{
|
||||
const urlRegex = /^\/(@[\w-]+)\/(.+)/
|
||||
const url = decodeURIComponent(req.url)
|
||||
console.debug ('GET',url)
|
||||
try {
|
||||
if (!urlRegex.test(url)) return res.sendStatus(404)
|
||||
const [, scpe, pkg ] = urlRegex.exec(url)
|
||||
const package = require (`${scpe}/${pkg}/package.json`)
|
||||
const tarball = `${scpe.slice(1)}-${pkg}-${package.version}.tgz`
|
||||
// https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md
|
||||
res.json({
|
||||
"name": package.name,
|
||||
"dist-tags": {
|
||||
"latest": package.version
|
||||
},
|
||||
"versions": {
|
||||
[package.version]: {
|
||||
"name": package.name,
|
||||
"version": package.version,
|
||||
"dist": {
|
||||
"tarball": `${server.url}/-/${tarball}`
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND') return res.sendStatus(404)
|
||||
console.error(e); throw e
|
||||
}
|
||||
})
|
||||
|
||||
const server = app.listen(port, ()=>{
|
||||
const url = server.url = `http://localhost:${server.address().port}`
|
||||
console.log (`npm set ${scope}:registry=${url}`)
|
||||
exec(`npm set ${scope}:registry=${url}`)
|
||||
console.log (`${scope} registry listening on ${url}`)
|
||||
})
|
||||
|
||||
|
||||
const _exit = ()=>{
|
||||
server.close()
|
||||
exec(`npm conf rm "${scope}:registry"`, ()=> { process.exit() })
|
||||
}
|
||||
|
||||
process.on ('SIGTERM',_exit)
|
||||
process.on ('SIGHUP',_exit)
|
||||
process.on ('SIGINT',_exit)
|
||||
process.on ('SIGUSR2',_exit)
|
||||
20
.vscode/launch.json
vendored
20
.vscode/launch.json
vendored
@@ -13,7 +13,7 @@
|
||||
"<node_internals>/**",
|
||||
"**/node_modules/**",
|
||||
"**/cds/lib/lazy.js",
|
||||
"**/cds/lib/req/cds-context.js",
|
||||
"**/cds/lib/req/cls.js",
|
||||
"**/odata-v4/okra/**"
|
||||
]
|
||||
},
|
||||
@@ -26,24 +26,10 @@
|
||||
"<node_internals>/**",
|
||||
"**/node_modules/**",
|
||||
"**/cds/lib/lazy.js",
|
||||
"**/cds/lib/req/cds-context.js",
|
||||
"**/cds/lib/req/cls.js",
|
||||
"**/odata-v4/okra/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Debug Mocha Tests",
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"port": 9229,
|
||||
"continueOnAttach": true,
|
||||
"skipFiles": [
|
||||
"<node_internals>/**",
|
||||
"**/node_modules/**",
|
||||
"**/cds/lib/lazy.js",
|
||||
"**/cds/lib/req/cds-context.js",
|
||||
"**/odata-v4/okra/**",
|
||||
]
|
||||
},
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
|
||||
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@@ -10,11 +10,10 @@
|
||||
"<node_internals>/**",
|
||||
"**/node_modules/**",
|
||||
"**/cds/lib/lazy.js",
|
||||
"**/cds/lib/req/cds-context.js",
|
||||
"**/cds/lib/req/cls.js",
|
||||
"**/odata-v4/okra/**"
|
||||
]
|
||||
},
|
||||
"mochaExplorer.debuggerConfig": "Debug Mocha Tests",
|
||||
"mochaExplorer.parallel": true,
|
||||
"eslint.validate": [
|
||||
"cds",
|
||||
@@ -23,5 +22,5 @@
|
||||
"csv (semicolon)",
|
||||
"tsv",
|
||||
"tab"
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -4,21 +4,15 @@
|
||||
* currencies, if not obtained through @capire/common.
|
||||
*/
|
||||
|
||||
module.exports = async (tx)=>{
|
||||
module.exports = async ()=>{
|
||||
|
||||
const has_common = tx.model.definitions['sap.common.Currencies']?.elements.numcode
|
||||
if (has_common) return
|
||||
|
||||
const already_filled = await tx.exists('sap.common.Currencies',{code:'EUR'})
|
||||
if (already_filled) return
|
||||
|
||||
await tx.run (INSERT.into ('sap.common.Currencies') .columns (
|
||||
[ 'code', 'symbol', 'name' ]
|
||||
await UPSERT.into ('sap.common.Currencies') .columns (
|
||||
'code','symbol','name'
|
||||
) .rows (
|
||||
[ 'EUR', '€', 'Euro' ],
|
||||
[ 'USD', '$', 'US Dollar' ],
|
||||
[ 'GBP', '£', 'British Pound' ],
|
||||
[ 'ILS', '₪', 'Shekel' ],
|
||||
[ 'JPY', '¥', 'Yen' ],
|
||||
))
|
||||
[ 'EUR','€','Euro' ],
|
||||
[ 'USD','$','US Dollar' ],
|
||||
[ 'GBP','£','British Pound' ],
|
||||
[ 'ILS','₪','Shekel' ],
|
||||
[ 'JPY','¥','Yen' ],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
"[production]": { "kind": "enterprise-messaging" }
|
||||
},
|
||||
"db": {
|
||||
"kind": "sql"
|
||||
"kind": "sql",
|
||||
"schema_evolution": "auto"
|
||||
}
|
||||
},
|
||||
"log": { "service": true }
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
}
|
||||
},
|
||||
"db": {
|
||||
"kind": "sql"
|
||||
"kind": "sql",
|
||||
"schema_evolution": "auto"
|
||||
},
|
||||
"db-ext": {
|
||||
"[development]": {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// install OData v2 adapter
|
||||
const cds = require("@sap/cds")
|
||||
const proxy = require('@sap/cds-odata-v2-adapter-proxy')
|
||||
const opts = global.it ? { target:'auto' } : {} // for tests, set 'auto' to detect port dynamically
|
||||
cds.on('bootstrap', app => app.use(proxy(opts))) // install proxy
|
||||
cds.log('cov2ap','silent') // suppress anoying log outpout, e.g. for `npm run mocha -- --reporter nyan`
|
||||
|
||||
module.exports = require('@capire/bookstore/server.js')
|
||||
// install OData v2 adapter
|
||||
const proxy = require('@sap/cds-odata-v2-adapter-proxy')
|
||||
const proxyOpts = global.it ? { target:'auto' } : {} // for tests, set 'auto' to detect port dynamically
|
||||
cds.on('bootstrap', app => app.use(proxy(proxyOpts)))
|
||||
|
||||
module.exports = require('@capire/bookstore/server.js')
|
||||
3401
package-lock.json
generated
3401
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@@ -24,20 +24,18 @@
|
||||
"chai": "^4.3.4",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chai-subset": "^1.6.0",
|
||||
"eslint": "^8.9",
|
||||
"semver": "^7",
|
||||
"sqlite3": "^5",
|
||||
"@sap/eslint-plugin-cds": "^2.6.0",
|
||||
"eslint-plugin-cloud-cap-samples": "file:.eslint"
|
||||
"sqlite3": "^5"
|
||||
},
|
||||
"scripts": {
|
||||
"cleanup": "rm -rf node_modules && rm -rf */node_modules && rm -rf */*/node_modules",
|
||||
"registry": "node .registry/server.js",
|
||||
"bookshop": "cds watch bookshop",
|
||||
"fiori": "cds watch fiori",
|
||||
"hello": "cds watch hello",
|
||||
"media": "cds watch media",
|
||||
"mocha": "CDS_TEST_SILENT=y npx mocha",
|
||||
"jest": "npx jest --silent",
|
||||
"mocha": "npx mocha || echo",
|
||||
"jest": "npx jest",
|
||||
"start": "cds watch fiori",
|
||||
"test": "npm run jest -- --silent",
|
||||
"test:hello": "cd hello && npm test"
|
||||
@@ -50,8 +48,7 @@
|
||||
},
|
||||
"mocha": {
|
||||
"recursive": true,
|
||||
"parallel": true,
|
||||
"timeout": 6666
|
||||
"parallel": true
|
||||
},
|
||||
"license": "SAP SAMPLE CODE LICENSE",
|
||||
"private": true
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
subject;rating;reviewer;title;text
|
||||
201;5;bob;Intriguing;Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
||||
201;4;bob;Fascinating;Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Id diam maecenas ultricies mi eget mauris pharetra et. Risus at ultrices mi tempus imperdiet nulla malesuada pellentesque. Pulvinar mattis nunc sed blandit libero. Facilisis magna etiam tempor orci eu. Nec sagittis aliquam malesuada bibendum arcu. Eu consequat ac felis donec. Ultricies tristique nulla aliquet enim tortor at auctor urna nunc. Tortor posuere ac ut consequat semper viverra nam libero. Amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor. Scelerisque purus semper eget duis at tellus. Elementum tempus egestas sed sed risus pretium. Arcu dictum varius duis at. Amet luctus venenatis lectus magna fringilla urna. Eget velit aliquet sagittis id consectetur purus ut faucibus. Vitae auctor eu augue ut lectus. Fermentum iaculis eu non diam phasellus vestibulum.
|
||||
207;2;bob;What is this?;Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Libero justo laoreet sit amet cursus sit amet dictum. Nunc faucibus a pellentesque sit. Dis parturient montes nascetur ridiculus mus mauris vitae ultricies. Enim nunc faucibus a pellentesque. Commodo quis imperdiet massa tincidunt nunc pulvinar sapien. Cras ornare arcu dui vivamus. Facilisi etiam dignissim diam quis enim lobortis. Et molestie ac feugiat sed. Urna neque viverra justo nec ultrices dui. Ullamcorper a lacus vestibulum sed arcu non. Volutpat ac tincidunt vitae semper quis. Dignissim sodales ut eu sem. Feugiat in fermentum posuere urna nec. At augue eget arcu dictum varius.
|
||||
251;3;bob;It's dark...;Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Suscipit tellus mauris a diam. Velit aliquet sagittis id consectetur purus ut. Viverra adipiscing at in tellus integer. Vitae elementum curabitur vitae nunc. Mattis ullamcorper velit sed ullamcorper morbi. Diam quis enim lobortis scelerisque. Auctor neque vitae tempus quam pellentesque nec nam aliquam. Semper auctor neque vitae tempus. Quis eleifend quam adipiscing vitae proin. Neque convallis a cras semper auctor neque vitae. Imperdiet massa tincidunt nunc pulvinar sapien et ligula. Sit amet consectetur adipiscing elit ut aliquam purus. Pretium quam vulputate dignissim suspendisse.
|
||||
ID;subject;rating;reviewer;title;text
|
||||
1223a37c-9dca-4c4c-a629-9dd93b947864;201;5;bob;Intriguing;Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
||||
ae275d4f-1fb5-491b-ba6e-79b339e1edef;201;4;bob;Fascinating;Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Id diam maecenas ultricies mi eget mauris pharetra et. Risus at ultrices mi tempus imperdiet nulla malesuada pellentesque. Pulvinar mattis nunc sed blandit libero. Facilisis magna etiam tempor orci eu. Nec sagittis aliquam malesuada bibendum arcu. Eu consequat ac felis donec. Ultricies tristique nulla aliquet enim tortor at auctor urna nunc. Tortor posuere ac ut consequat semper viverra nam libero. Amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor. Scelerisque purus semper eget duis at tellus. Elementum tempus egestas sed sed risus pretium. Arcu dictum varius duis at. Amet luctus venenatis lectus magna fringilla urna. Eget velit aliquet sagittis id consectetur purus ut faucibus. Vitae auctor eu augue ut lectus. Fermentum iaculis eu non diam phasellus vestibulum.
|
||||
3fffe4b7-d34f-4fd3-9aab-f609f41539cc;207;2;bob;What is this?;Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Libero justo laoreet sit amet cursus sit amet dictum. Nunc faucibus a pellentesque sit. Dis parturient montes nascetur ridiculus mus mauris vitae ultricies. Enim nunc faucibus a pellentesque. Commodo quis imperdiet massa tincidunt nunc pulvinar sapien. Cras ornare arcu dui vivamus. Facilisi etiam dignissim diam quis enim lobortis. Et molestie ac feugiat sed. Urna neque viverra justo nec ultrices dui. Ullamcorper a lacus vestibulum sed arcu non. Volutpat ac tincidunt vitae semper quis. Dignissim sodales ut eu sem. Feugiat in fermentum posuere urna nec. At augue eget arcu dictum varius.
|
||||
71c037b3-767d-4f5d-9e90-90b894a2043a;251;3;bob;It's dark...;Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Suscipit tellus mauris a diam. Velit aliquet sagittis id consectetur purus ut. Viverra adipiscing at in tellus integer. Vitae elementum curabitur vitae nunc. Mattis ullamcorper velit sed ullamcorper morbi. Diam quis enim lobortis scelerisque. Auctor neque vitae tempus quam pellentesque nec nam aliquam. Semper auctor neque vitae tempus. Quis eleifend quam adipiscing vitae proin. Neque convallis a cras semper auctor neque vitae. Imperdiet massa tincidunt nunc pulvinar sapien et ligula. Sit amet consectetur adipiscing elit ut aliquam purus. Pretium quam vulputate dignissim suspendisse.
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# Overview of Samples
|
||||
|
||||
The following list gives an overview of the samples provided in subdirectories.
|
||||
Each sub directory essentially is an individual npm package arranged in an [all-in-one monorepo](#all-in-one-monorepo) umbrella setup.
|
||||
Each sub directory essentially is an individual npm package arranged in an [all-in-one monorepo](all-in-one-monorepo) umbrella setup.
|
||||
|
||||
|
||||
## [@capire/hello-world](hello)
|
||||
|
||||
@@ -3,9 +3,8 @@ const cds = require('@sap/cds/lib')
|
||||
describe('cap/samples - Custom Handlers', () => {
|
||||
|
||||
const { GET, POST, expect } = cds.test(__dirname+'/../bookshop')
|
||||
beforeAll(()=>{
|
||||
cds.User.default = cds.User.Privileged // hard core monkey patch
|
||||
})
|
||||
if (cds.User.default) cds.User.default = cds.User.Privileged // hard core monkey patch
|
||||
else cds.User = cds.User.Privileged // hard core monkey patch for older cds releases
|
||||
|
||||
it('should reject out-of-stock orders', async () => {
|
||||
await POST `/browse/submitOrder ${{ book: 201, quantity: 5 }}`
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
const cds = require('@sap/cds/lib')
|
||||
|
||||
describe('cap/samples - Fiori APIs - v2', function() {
|
||||
describe('cap/samples - Fiori APIs - v2', () => {
|
||||
|
||||
const { GET, expect, axios } = cds.test ('@capire/fiori', '--with-mocks')
|
||||
axios.defaults.auth = { username: 'alice', password: 'admin' }
|
||||
|
||||
// if (this.timeout) this.timeout(1e6)
|
||||
|
||||
it('serves $metadata documents in v2', async () => {
|
||||
const { headers, data } = await GET `/v2/browse/$metadata`
|
||||
expect(headers).to.contain({
|
||||
|
||||
@@ -16,21 +16,21 @@ describe('cap/samples - Hierarchical Data', ()=>{
|
||||
before ('bootstrap sqlite in-memory db...', async()=>{
|
||||
await cds.deploy (model) .to ('sqlite::memory:')
|
||||
expect (cds.db) .to.exist
|
||||
expect (cds.db.model) .to.exist
|
||||
expect (cds.db.model) .to.exist
|
||||
})
|
||||
|
||||
it ('supports deeply nested inserts', ()=> INSERT.into (Cats,
|
||||
{ ID:100, name:'Some Cats...', children:[
|
||||
{ ID:101, name:'Cat', children:[
|
||||
{ ID:102, name:'Kitty', children:[
|
||||
{ ID:103, name:'Kitty Cat', children:[
|
||||
{ ID:104, name:'Aristocat' } ]},
|
||||
{ ID:105, name:'Kitty Bat' } ]},
|
||||
{ ID:106, name:'Catwoman', children:[
|
||||
{ ID:107, name:'Catalina' } ]} ]},
|
||||
{ ID:108, name:'Catweazle' }
|
||||
]}
|
||||
))
|
||||
{ ID:100, name:'Some Cats...', children:[
|
||||
{ ID:101, name:'Cat', children:[
|
||||
{ ID:102, name:'Kitty', children:[
|
||||
{ ID:103, name:'Kitty Cat', children:[
|
||||
{ ID:104, name:'Aristocat' } ]},
|
||||
{ ID:105, name:'Kitty Bat' } ]},
|
||||
{ ID:106, name:'Catwoman', children:[
|
||||
{ ID:107, name:'Catalina' } ]} ]},
|
||||
{ ID:108, name:'Catweazle' }
|
||||
]}
|
||||
))
|
||||
|
||||
it ('supports nested reads', async()=>{
|
||||
if (require('semver').gte(cds.version, '5.9.0')) {
|
||||
@@ -101,12 +101,12 @@ describe('cap/samples - Hierarchical Data', ()=>{
|
||||
})
|
||||
|
||||
it ('supports cascaded deletes', async()=>{
|
||||
const affectedRows = await DELETE.from (Cats) .where ({ID:[102,106]})
|
||||
expect (affectedRows) .to.be.greaterThan (0)
|
||||
const affectedRows = await DELETE.from (Cats) .where ({ID:[102,106]})
|
||||
expect (affectedRows) .to.be.greaterThan (0)
|
||||
const expected = [
|
||||
{ ID:100, name:'Some Cats...' },
|
||||
{ ID:101, name:'Cat' },
|
||||
{ ID:108, name:'Catweazle' }
|
||||
{ ID:100, name:'Some Cats...' },
|
||||
{ ID:101, name:'Cat' },
|
||||
{ ID:108, name:'Catweazle' }
|
||||
]
|
||||
expect ( await SELECT`ID,name`.from(Cats) ).to.eql (expected)
|
||||
})
|
||||
|
||||
10
test/localized-data/package.json
Normal file
10
test/localized-data/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"cds": {
|
||||
"requires": {
|
||||
"db": {
|
||||
"kind": "sql",
|
||||
"schema_evolution": "auto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,8 @@
|
||||
const cds = require('@sap/cds/lib')
|
||||
|
||||
describe('cap/samples - Localized Data', () => {
|
||||
|
||||
const { GET, expect } = cds.test (__dirname)
|
||||
beforeAll(()=>{
|
||||
cds.User.default = cds.User.Privileged // hard core monkey patch
|
||||
})
|
||||
|
||||
const { GET, expect, cds } = require('@sap/cds/lib').test (__dirname)
|
||||
if (cds.User.default) cds.User.default = cds.User.Privileged // hard core monkey patch
|
||||
else cds.User = cds.User.Privileged // hard core monkey patch for older cds releases
|
||||
|
||||
it('serves localized $metadata documents', async () => {
|
||||
const { data } = await GET(`/browse/$metadata?sap-language=de`, { headers: { 'accept-language': 'de' }})
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
const cds = require('@sap/cds/lib')
|
||||
const {resolve} = require('path')
|
||||
|
||||
describe('cap/samples - Messaging', ()=>{
|
||||
|
||||
const { expect } = cds.test.in(__dirname,'..')
|
||||
const { expect } = cds.test
|
||||
const _model = '@capire/reviews'
|
||||
const Reviews = 'sap.capire.reviews.Reviews'
|
||||
beforeAll(()=>{
|
||||
cds.User.default = cds.User.Privileged // hard core monkey patch
|
||||
})
|
||||
if (cds.User.default) cds.User.default = cds.User.Privileged // hard core monkey patch
|
||||
else cds.User = cds.User.Privileged // hard core monkey patch for older cds releases
|
||||
|
||||
beforeAll(() => { cds.root = resolve(__dirname, '..') })
|
||||
afterAll(() => { cds.root = process.cwd() })
|
||||
|
||||
it ('should bootstrap sqlite in-memory db', async()=>{
|
||||
const db = await cds.deploy (_model) .to ('sqlite::memory:')
|
||||
@@ -32,7 +35,6 @@ describe('cap/samples - Messaging', ()=>{
|
||||
|
||||
it ('should add review', async ()=>{
|
||||
const review = { subject: "201", title: "Captivating", rating: ++N }
|
||||
cds._debug = 1
|
||||
const response = await srv.create ('Reviews') .entries (review)
|
||||
expect (response) .to.containSubset (review)
|
||||
})
|
||||
|
||||
@@ -4,6 +4,47 @@ describe('cap/samples - Bookshop APIs', () => {
|
||||
const { GET, expect, axios } = cds.test ('@capire/bookshop')
|
||||
axios.defaults.auth = { username: 'alice', password: 'admin' }
|
||||
|
||||
// Genres
|
||||
const Drama = {
|
||||
"name": "Drama",
|
||||
"descr": null,
|
||||
"ID": 11,
|
||||
"parent_ID": 10
|
||||
}
|
||||
const Mystery = {
|
||||
"name": "Mystery",
|
||||
"descr": null,
|
||||
"ID": 16,
|
||||
"parent_ID": 10
|
||||
}
|
||||
const Romance = {
|
||||
"name": "Romance",
|
||||
"descr": null,
|
||||
"ID": 15,
|
||||
"parent_ID": 10
|
||||
}
|
||||
|
||||
// Currencies
|
||||
const GBP = {
|
||||
"name": "British Pound",
|
||||
"descr": null,
|
||||
"code": "GBP",
|
||||
"symbol": "£"
|
||||
}
|
||||
const USD = {
|
||||
"name": "US Dollar",
|
||||
"descr": null,
|
||||
"code": "USD",
|
||||
"symbol": "$"
|
||||
}
|
||||
const JPY = {
|
||||
"name": "Yen",
|
||||
"descr": null,
|
||||
"code": "JPY",
|
||||
"symbol": "¥"
|
||||
}
|
||||
|
||||
|
||||
it('serves $metadata documents in v4', async () => {
|
||||
const { headers, status, data } = await GET `/browse/$metadata`
|
||||
expect(status).to.equal(200)
|
||||
@@ -16,9 +57,6 @@ describe('cap/samples - Bookshop APIs', () => {
|
||||
})
|
||||
|
||||
it('serves ListOfBooks?$expand=genre,currency', async () => {
|
||||
const Mystery = { ID: 16, name: 'Mystery', descr: null, parent_ID: 10 }
|
||||
const Romance = { ID: 15, name: 'Romance', descr: null, parent_ID: 10 }
|
||||
const USD = { code: 'USD', name: 'US Dollar', descr: null, symbol: '$' }
|
||||
const { data } = await GET `/browse/ListOfBooks ${{
|
||||
params: { $search: 'Po', $select: `title,author`, $expand:`genre,currency` },
|
||||
}}`
|
||||
@@ -88,10 +126,14 @@ describe('cap/samples - Bookshop APIs', () => {
|
||||
})
|
||||
|
||||
it('serves user info', async () => {
|
||||
const { data: alice } = await GET `/user/me`
|
||||
expect(alice).to.containSubset({ id: 'alice', locale:'en' })
|
||||
const { data: joe } = await GET (`/user/me`, {auth: { username: 'joe' }})
|
||||
expect(joe).to.containSubset({ id: 'joe', locale:'en' })
|
||||
{
|
||||
const { data } = await GET (`/user/me`)
|
||||
expect(data).to.containSubset({ id: 'alice', locale:'en' })
|
||||
}
|
||||
{
|
||||
const { data } = await GET (`/user/me`, {auth: { username: 'joe' }})
|
||||
expect(data).to.containSubset({ id: 'joe', locale:'en' })
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
57
test/registry.test.js
Normal file
57
test/registry.test.js
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
const cds = require('@sap/cds/lib')
|
||||
const { fork } = require('child_process')
|
||||
const { resolve } = require('path')
|
||||
const verbose = process.env.CDS_TEST_VERBOSE
|
||||
|
||||
describe('cap/samples - Local NPM registry', () => {
|
||||
|
||||
const { expect } = cds.test
|
||||
// ||true
|
||||
|
||||
let registry
|
||||
let axios
|
||||
const cwd = resolve(__dirname, '..')
|
||||
|
||||
before(async ()=> {
|
||||
const env = Object.assign(process.env, {PORT:'0'})
|
||||
const res = await exec (resolve(cwd, '.registry/server.js'), {cwd, stdio: 'pipe', env})
|
||||
registry = res.cp
|
||||
axios = require('axios').create ({ baseURL: res.url, validateStatus: (status)=>status<500 })
|
||||
})
|
||||
|
||||
after(done => { registry.once('exit',done); registry.kill() })
|
||||
|
||||
for (const mod of ['bookshop', 'data-viewer', 'fiori','orders','reviews']) {
|
||||
it(`should serve ${mod}`, async () => {
|
||||
const resp = await axios.get(`/@capire/${mod}`)
|
||||
expect(resp.data).to.containSubset({name: `@capire/${mod}`, versions:{}})
|
||||
const versions = Object.values(resp.data.versions)
|
||||
await axios.get(versions[0].dist.tarball)
|
||||
})
|
||||
}
|
||||
it(`should return 404 for unknown packages`, async () => {
|
||||
let resp = await axios.get(`/@capire/foo`)
|
||||
expect(resp.status).to.equal(404)
|
||||
resp = await axios.get(`/foo`)
|
||||
expect(resp.status).to.equal(404)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
function exec (script, opts) {
|
||||
return new Promise((resolve, reject)=> {
|
||||
const cp = fork (script, [], opts)
|
||||
.on('error', err => reject(new Error(err)))
|
||||
cp.stdout.on('data', chunk => {
|
||||
if (verbose) console.log(chunk.toString())
|
||||
if (chunk.toString().match(/listening.*(http:.*:\d+)/i)) {
|
||||
resolve({cp, url:RegExp.$1})
|
||||
}
|
||||
})
|
||||
cp.stderr.on('data', chunk => {
|
||||
if (verbose) console.error(chunk.toString())
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user