Compare commits
50 Commits
audit-logg
...
trying-esm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
518429e2a0 | ||
|
|
02000f4a94 | ||
|
|
8f5c33f4f5 | ||
|
|
a893184736 | ||
|
|
9370d0544e | ||
|
|
ee4dcf116c | ||
|
|
58cef5558d | ||
|
|
7753cda65d | ||
|
|
df57a9d8d0 | ||
|
|
2d92b851f1 | ||
|
|
e157fc8a92 | ||
|
|
3b69a80975 | ||
|
|
b80ba7445d | ||
|
|
b733643f2a | ||
|
|
bf317bc2c9 | ||
|
|
bbebff4066 | ||
|
|
eb75394044 | ||
|
|
b8f65b687f | ||
|
|
c49c9691bd | ||
|
|
7e4bc0985e | ||
|
|
912271338d | ||
|
|
bbf1194a09 | ||
|
|
529c431518 | ||
|
|
3f85676edd | ||
|
|
959c07cee3 | ||
|
|
8cc09fde38 | ||
|
|
bb55c432c9 | ||
|
|
5fc86d45ad | ||
|
|
e86d0dc3a2 | ||
|
|
a661fb2d45 | ||
|
|
bfe0c831d6 | ||
|
|
cad615a662 | ||
|
|
7101c58920 | ||
|
|
07dc1e88b3 | ||
|
|
6f8d74dc9a | ||
|
|
ec57c5ea48 | ||
|
|
c040a47279 | ||
|
|
30bfd70c49 | ||
|
|
6fb9581cf1 | ||
|
|
e87d6cdfc5 | ||
|
|
29ea2bc2da | ||
|
|
12574271ac | ||
|
|
17b5cc1ad2 | ||
|
|
26ca7f54ad | ||
|
|
573e78253d | ||
|
|
a7511ed677 | ||
|
|
f1289b436b | ||
|
|
984ea2133b | ||
|
|
179d301acb | ||
|
|
bbf20b1ca3 |
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
directory: /
|
||||
versioning-strategy: increase-if-necessary
|
||||
schedule:
|
||||
interval: daily
|
||||
@@ -16,7 +16,8 @@ app.use('/-/:tarball', (req,res,next) => {
|
||||
console.debug ('GET', req.params)
|
||||
try {
|
||||
const { tarball } = req.params
|
||||
const [, pkg ] = /^\w+-(\w+)/.exec(tarball)
|
||||
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)
|
||||
@@ -31,7 +32,7 @@ app.use('/-/:tarball', (req,res,next) => {
|
||||
app.use('/-', express.static(__dirname))
|
||||
|
||||
app.get('/*', (req,res)=>{
|
||||
const urlRegex = /^\/(@\w+)\/(\w+)/
|
||||
const urlRegex = /^\/(@[\w-]+)\/(.+)/
|
||||
const url = decodeURIComponent(req.url)
|
||||
console.debug ('GET',url)
|
||||
try {
|
||||
|
||||
@@ -3,14 +3,15 @@ const $ = sel => document.querySelector(sel)
|
||||
const GET = (url) => axios.get('/browse'+url)
|
||||
const POST = (cmd,data) => axios.post('/browse'+cmd,data)
|
||||
|
||||
const books = new Vue ({
|
||||
const books = Vue.createApp ({
|
||||
|
||||
el:'#app',
|
||||
|
||||
data: {
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
book: undefined,
|
||||
order: { quantity:1, succeeded:'', failed:'' }
|
||||
order: { quantity:1, succeeded:'', failed:'' },
|
||||
user: undefined
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -37,12 +38,30 @@ const books = new Vue ({
|
||||
book.stock = res.data.stock
|
||||
books.order = { quantity, succeeded: `Successfully ordered ${quantity} item(s).` }
|
||||
} catch (e) {
|
||||
books.order = { quantity, failed: e.response.data.error.message }
|
||||
books.order = { quantity, failed: e.response.data.error ? e.response.data.error.message : e.response.data }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async login() {
|
||||
try {
|
||||
const { data:user } = await axios.post('/user/login',{})
|
||||
if (user.id !== 'anonymous') books.user = user
|
||||
} catch (err) { books.user = { id: err.message } }
|
||||
},
|
||||
|
||||
async getUserInfo() {
|
||||
try {
|
||||
const { data:user } = await axios.get('/user/me')
|
||||
if (user.id !== 'anonymous') books.user = user
|
||||
} catch (err) { books.user = { id: err.message } }
|
||||
},
|
||||
}
|
||||
})
|
||||
}).mount("#app")
|
||||
|
||||
// initially fill list of books
|
||||
books.fetch()
|
||||
books.getUserInfo()
|
||||
books.fetch() // initially fill list of books
|
||||
|
||||
document.addEventListener('keydown', (event) => {
|
||||
// hide user info on request
|
||||
if (event.key === 'u') books.user = undefined
|
||||
})
|
||||
|
||||
@@ -5,19 +5,32 @@
|
||||
<title> Capire Books </title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/primitive-ui/dist/css/main.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
|
||||
<style>
|
||||
.hovering tr:hover td { color:cyan; background: #123; cursor: pointer; }
|
||||
.rating-stars { color:teal }
|
||||
.succeeded { color:teal }
|
||||
.failed { color:red }
|
||||
.user {text-align: end; color: grey;}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="small-container", style="margin-top: 70px;">
|
||||
<div id='app'>
|
||||
|
||||
<h1> {{ document.title }} </h1>
|
||||
<form class="user" @submit.prevent="login">
|
||||
<div v-if="user">
|
||||
<div v-if="user.tenant">Tenant: {{ user.tenant }}</div>
|
||||
<div> User: {{ user.id }}</div>
|
||||
<div>Locale: {{ user.locale }}</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<input type="submit" value="Login" class="muted-button">
|
||||
<!-- <a href="/user/login()">Login</a> -->
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<h1> Capire Books </h1>
|
||||
|
||||
<input type="text" placeholder="Search..." @input="search">
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* currencies, if not obtained through @capire/common.
|
||||
*/
|
||||
|
||||
module.exports = async (db)=>{
|
||||
export default async (db)=>{
|
||||
|
||||
const has_common = db.model.definitions['sap.common.Currencies'].elements.numcode
|
||||
if (has_common) return
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
const { CatalogService } = require('./srv/cat-service')
|
||||
module.exports = { CatalogService }
|
||||
import { CatalogService } from './srv/cat-service.js'
|
||||
export { CatalogService }
|
||||
|
||||
@@ -2,10 +2,18 @@
|
||||
"name": "@capire/bookshop",
|
||||
"version": "1.0.0",
|
||||
"description": "A simple self-contained bookshop service.",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"app",
|
||||
"srv",
|
||||
"db",
|
||||
"index.cds",
|
||||
"index.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"@sap/cds": "^5.0.4",
|
||||
"@sap/cds": ">=5.9",
|
||||
"express": "^4.17.1",
|
||||
"passport": "0.4.1"
|
||||
"passport": ">=0.4.1"
|
||||
},
|
||||
"scripts": {
|
||||
"genres": "cds serve test/genres.cds",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const cds = require('@sap/cds')
|
||||
import cds from '@sap/cds'
|
||||
|
||||
module.exports = cds.service.impl (function(){
|
||||
export default cds.service.impl (function(){
|
||||
this.before ('NEW','Authors', genid)
|
||||
this.before ('NEW','Books', genid)
|
||||
})
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const cds = require('@sap/cds')
|
||||
import cds from '@sap/cds'
|
||||
|
||||
class CatalogService extends cds.ApplicationService { init(){
|
||||
export class CatalogService extends cds.ApplicationService { init(){
|
||||
|
||||
const { Books } = cds.entities ('sap.capire.bookshop')
|
||||
const { Books } = this.entities ('sap.capire.bookshop')
|
||||
|
||||
// Reduce stock of ordered books if available stock suffices
|
||||
this.on ('submitOrder', async req => {
|
||||
@@ -24,5 +24,3 @@ class CatalogService extends cds.ApplicationService { init(){
|
||||
|
||||
return super.init()
|
||||
}}
|
||||
|
||||
module.exports = { CatalogService }
|
||||
|
||||
15
bookshop/srv/user-service.cds
Normal file
15
bookshop/srv/user-service.cds
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Exposes user information
|
||||
*/
|
||||
service UserService {
|
||||
/**
|
||||
* The current user
|
||||
*/
|
||||
@odata.singleton entity me {
|
||||
id : String; // user id
|
||||
locale : String;
|
||||
tenant : String;
|
||||
}
|
||||
|
||||
action login() returns me;
|
||||
}
|
||||
10
bookshop/srv/user-service.js
Normal file
10
bookshop/srv/user-service.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import cds from '@sap/cds'
|
||||
|
||||
export default class UserService extends cds.Service { init(){
|
||||
this.on('READ', 'me', ({ tenant, user, locale }) => ({ id: user.id, locale, tenant }))
|
||||
this.on('login', (req) => {
|
||||
if (req.user._is_anonymous)
|
||||
req._.res.set('WWW-Authenticate','Basic realm="Users"').sendStatus(401)
|
||||
else return this.read('me')
|
||||
})
|
||||
}}
|
||||
@@ -16,9 +16,9 @@ GET {{server}}/browse/$metadata
|
||||
|
||||
### ------------------------------------------------------------------------
|
||||
# Browse Books as any user
|
||||
GET {{server}}/browse/Books?
|
||||
GET {{server}}/browse/ListOfBooks?
|
||||
# &$select=title,stock
|
||||
# &$expand=currency
|
||||
&$expand=genre
|
||||
# &sap-language=de
|
||||
{{me}}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"@capire/orders": "*",
|
||||
"@capire/common": "*",
|
||||
"@capire/data-viewer": "*",
|
||||
"@sap/cds": "^5",
|
||||
"@sap/cds": ">=5",
|
||||
"express": "^4.17.1"
|
||||
},
|
||||
"cds": {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"description": "A generic browser for data",
|
||||
"dependencies": {
|
||||
"@sap/cds": "^5.0.4"
|
||||
"@sap/cds": ">=5.0.4"
|
||||
},
|
||||
"files": [
|
||||
"app",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
},
|
||||
"dataSources": {
|
||||
"AdminService": {
|
||||
"uri": "/admin/",
|
||||
"uri": "admin/",
|
||||
"type": "OData",
|
||||
"settings": {
|
||||
"odataVersion": "4.0"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"i18n": "i18n/i18n.properties",
|
||||
"dataSources": {
|
||||
"AdminService": {
|
||||
"uri": "/admin/",
|
||||
"uri": "admin/",
|
||||
"type": "OData",
|
||||
"settings": {
|
||||
"odataVersion": "4.0"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
},
|
||||
"dataSources": {
|
||||
"CatalogService": {
|
||||
"uri": "/browse/",
|
||||
"uri": "browse/",
|
||||
"type": "OData",
|
||||
"settings": {
|
||||
"odataVersion": "4.0"
|
||||
@@ -32,7 +32,7 @@
|
||||
"renameTo": "ID"
|
||||
},
|
||||
"Authors.books.ID": {
|
||||
"renameTo": "ID"
|
||||
"renameTo": "ID"
|
||||
}
|
||||
},
|
||||
"additionalParameters": "ignored"
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
<script id="sap-ushell-bootstrap" src="https://sapui5.hana.ondemand.com/test-resources/sap/ushell/bootstrap/sandbox.js"></script>
|
||||
<script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
|
||||
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
|
||||
data-sap-ui-compatVersion="edge"
|
||||
data-sap-ui-theme="sap_fiori_3"
|
||||
data-sap-ui-frameOptions="allow"
|
||||
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
|
||||
data-sap-ui-compatVersion="edge"
|
||||
data-sap-ui-theme="sap_horizon"
|
||||
data-sap-ui-frameOptions="allow"
|
||||
></script>
|
||||
<script>
|
||||
sap.ui.getCore().attachInit(()=> sap.ushell.Container.createRenderer().placeAt("content"))
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@capire/bookstore": "*",
|
||||
"@sap/cds": "^5",
|
||||
"@sap/cds": ">=5",
|
||||
"express": "^4.17.1",
|
||||
"passport": "^0.4.1"
|
||||
"passport": ">=0.4.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cds run --in-memory?",
|
||||
@@ -14,7 +14,7 @@
|
||||
"cds": {
|
||||
"requires": {
|
||||
"auth": {
|
||||
"strategy": "dummy"
|
||||
"kind": "dummy-auth"
|
||||
},
|
||||
"ReviewsService": {
|
||||
"kind": "odata",
|
||||
@@ -51,4 +51,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
"start:ts": "cds-ts serve srv/world.cds"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sap/cds": "^5.0.4"
|
||||
"@sap/cds": ">=5.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/node": "^16.11.6",
|
||||
"@types/jest": "*",
|
||||
"@types/node": "*",
|
||||
"ts-jest": "^27.0.2",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
|
||||
<script id="sap-ushell-bootstrap" src="https://sapui5.hana.ondemand.com/test-resources/sap/ushell/bootstrap/sandbox.js"></script>
|
||||
<script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
|
||||
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
|
||||
data-sap-ui-compatVersion="edge"
|
||||
data-sap-ui-theme="sap_fiori_3"
|
||||
data-sap-ui-frameOptions="allow"
|
||||
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
|
||||
data-sap-ui-compatVersion="edge"
|
||||
data-sap-ui-theme="sap_horizon"
|
||||
data-sap-ui-frameOptions="allow"
|
||||
></script>
|
||||
<script>
|
||||
sap.ui.getCore().attachInit(()=> sap.ushell.Container.createRenderer().placeAt("content"))
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@capire/common": "*",
|
||||
"@sap/cds": "^5"
|
||||
"@sap/cds": ">=5"
|
||||
}
|
||||
}
|
||||
5187
package-lock.json
generated
5187
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -14,13 +14,14 @@
|
||||
"@capire/media": "./media",
|
||||
"@capire/orders": "./orders",
|
||||
"@capire/reviews": "./reviews",
|
||||
"@sap/cds": "^5.5.3"
|
||||
"@sap/cds": ">=5.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.3.4",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chai-subset": "^1.6.0",
|
||||
"sqlite3": "npm:@mendix/sqlite3@^5"
|
||||
"semver": "^7",
|
||||
"sqlite3": "^5"
|
||||
},
|
||||
"scripts": {
|
||||
"cleanup": "rm -rf node_modules && rm -rf */node_modules && rm -rf */*/node_modules",
|
||||
|
||||
@@ -4,21 +4,21 @@ const GET = (url) => axios.get('/reviews'+url)
|
||||
const PUT = (cmd,data) => axios.patch('/reviews'+cmd,data)
|
||||
const POST = (cmd,data) => axios.post('/reviews'+cmd,data)
|
||||
|
||||
const reviews = new Vue ({
|
||||
const reviews = Vue.createApp ({
|
||||
|
||||
el:'#app',
|
||||
|
||||
data: {
|
||||
list: [],
|
||||
review: undefined,
|
||||
message: {},
|
||||
Ratings: Object.entries({
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
review: undefined,
|
||||
message: {},
|
||||
Ratings: Object.entries({
|
||||
5 : '★★★★★',
|
||||
4 : '★★★★',
|
||||
3 : '★★★',
|
||||
2 : '★★',
|
||||
1 : '★',
|
||||
}).reverse()
|
||||
}).reverse()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -66,7 +66,7 @@ const reviews = new Vue ({
|
||||
datetime: (d) => d && new Date(d).toLocaleString(),
|
||||
},
|
||||
|
||||
})
|
||||
}).mount("#app")
|
||||
|
||||
// initially fill list of my reviews
|
||||
reviews.fetch()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<title> Capire Reviews </title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/primitive-ui/dist/css/main.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
|
||||
<style>
|
||||
.hovering tr:hover td { color:cyan; background: #123; cursor: pointer; }
|
||||
.rating-stars { color:teal }
|
||||
@@ -18,7 +18,7 @@
|
||||
<body class="small-container", style="margin-top: 70px;">
|
||||
<div id='app'>
|
||||
|
||||
<h1> {{ document.title }} </h1>
|
||||
<h1> Capire Reviews </h1>
|
||||
|
||||
<input type="text" placeholder="Search..." @input="search">
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"index.cds"
|
||||
],
|
||||
"dependencies": {
|
||||
"@sap/cds": "^5",
|
||||
"@sap/cds": ">=5",
|
||||
"express": "^4.17.1"
|
||||
},
|
||||
"cds": {
|
||||
|
||||
@@ -81,6 +81,8 @@ describe('cds.ql → cqn', () => {
|
||||
.to.eql(SELECT('Foo','Boo').from('Bar'))
|
||||
.to.eql(SELECT(['Foo','Boo']).from('Bar'))
|
||||
.to.eql(SELECT `Bar` .columns `Foo, Boo`)
|
||||
.to.eql(SELECT `Bar` .columns `{ Foo, Boo }`)
|
||||
.to.eql(SELECT `Bar` .columns ('{ Foo, Boo }'))
|
||||
.to.eql(SELECT `Bar` .columns ('Foo','Boo'))
|
||||
.to.eql(SELECT `Bar` .columns (['Foo','Boo']))
|
||||
.to.eql(SELECT.from `Bar` .columns ('Foo','Boo'))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const cds = require('@sap/cds/lib')
|
||||
const { expect } = cds.test ('@capire/bookshop')
|
||||
|
||||
describe('Consuming Services locally', () => {
|
||||
describe('cap/samples - Consuming Services locally', () => {
|
||||
//
|
||||
it('bootstrapped the database successfully', ()=>{
|
||||
const { AdminService } = cds.services
|
||||
@@ -32,6 +32,27 @@ describe('Consuming Services locally', () => {
|
||||
})
|
||||
})
|
||||
}).where(`name like`, 'E%')
|
||||
if (require('semver').gte(cds.version, '5.9.0')) {
|
||||
expect(authors).to.containSubset([
|
||||
{
|
||||
name: 'Emily Brontë',
|
||||
books: [
|
||||
{
|
||||
title: 'Wuthering Heights',
|
||||
currency: { name: 'British Pound', symbol: '£' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Edgar Allen Poe',
|
||||
books: [
|
||||
{ title: 'The Raven', currency: { name: 'US Dollar', symbol: '$' } },
|
||||
{ title: 'Eleonora', currency: { name: 'US Dollar', symbol: '$' } },
|
||||
],
|
||||
},
|
||||
])
|
||||
return
|
||||
}
|
||||
expect(authors).to.containSubset([
|
||||
{
|
||||
name: 'Emily Brontë',
|
||||
|
||||
@@ -3,7 +3,7 @@ const { GET, POST, expect } = cds.test(__dirname+'/../bookshop')
|
||||
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
|
||||
|
||||
describe('Custom Handlers', () => {
|
||||
describe('cap/samples - Custom Handlers', () => {
|
||||
|
||||
it('should reject out-of-stock orders', async () => {
|
||||
await POST `/browse/submitOrder ${{ book: 201, quantity: 5 }}`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const cds = require('@sap/cds/lib')
|
||||
const { GET, expect } = cds.test (__dirname+'/../hello')
|
||||
|
||||
describe('Hello world!', () => {
|
||||
describe('cap/samples - Hello world!', () => {
|
||||
|
||||
it('should say hello with class impl', async () => {
|
||||
const {data} = await GET `/say/hello(to='world')`
|
||||
|
||||
@@ -13,7 +13,7 @@ const model = cds.compile.to.csn (`
|
||||
const {Categories:Cats} = model.definitions
|
||||
|
||||
|
||||
describe('Hierarchical Data', ()=>{
|
||||
describe('cap/samples - Hierarchical Data', ()=>{
|
||||
|
||||
before ('bootstrap sqlite in-memory db...', async()=>{
|
||||
await cds.deploy (model) .to ('sqlite::memory:')
|
||||
@@ -35,6 +35,21 @@ describe('Hierarchical Data', ()=>{
|
||||
))
|
||||
|
||||
it ('supports nested reads', async()=>{
|
||||
if (require('semver').gte(cds.version, '5.9.0')) {
|
||||
expect (await
|
||||
SELECT.one.from (Cats, c=>{
|
||||
c.ID, c.name.as('parent'), c.children (c=>{
|
||||
c.name.as('child')
|
||||
})
|
||||
}) .where ({name:'Cat'})
|
||||
) .to.eql (
|
||||
{ ID:101, parent:'Cat', children:[
|
||||
{ child:'Kitty' },
|
||||
{ child:'Catwoman' },
|
||||
]}
|
||||
)
|
||||
return
|
||||
}
|
||||
expect (await
|
||||
SELECT.one.from (Cats, c=>{
|
||||
c.ID, c.name.as('parent'), c.children (c=>{
|
||||
@@ -50,6 +65,25 @@ describe('Hierarchical Data', ()=>{
|
||||
})
|
||||
|
||||
it ('supports deeply nested reads', async()=>{
|
||||
if (require('semver').gte(cds.version, '5.9.0')) {
|
||||
expect (await SELECT.one.from (Cats, c=>{
|
||||
c.ID, c.name, c.children (
|
||||
c => { c.name },
|
||||
{levels:3}
|
||||
)
|
||||
}) .where ({name:'Cat'})
|
||||
) .to.eql (
|
||||
{ ID:101, name:'Cat', children:[
|
||||
{ name:'Kitty', children:[
|
||||
{ name:'Kitty Cat', children:[
|
||||
{ name:'Aristocat' }, ]}, // level 3
|
||||
{ name:'Kitty Bat', children:[] }, ]},
|
||||
{ name:'Catwoman', children:[
|
||||
{ name:'Catalina', children:[] } ]},
|
||||
]}
|
||||
)
|
||||
return
|
||||
}
|
||||
expect (await SELECT.one.from (Cats, c=>{
|
||||
c.ID, c.name, c.children (
|
||||
c => { c.name },
|
||||
|
||||
@@ -2,7 +2,7 @@ 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
|
||||
|
||||
describe('Localized Data', () => {
|
||||
describe('cap/samples - Localized Data', () => {
|
||||
|
||||
it('serves localized $metadata documents', async () => {
|
||||
const { data } = await GET`/browse/$metadata?sap-language=de`
|
||||
|
||||
@@ -4,7 +4,7 @@ const _model = '@capire/reviews'
|
||||
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
|
||||
|
||||
describe('Messaging', ()=>{
|
||||
describe('cap/samples - Messaging', ()=>{
|
||||
|
||||
it ('should bootstrap sqlite in-memory db', async()=>{
|
||||
const db = await cds.deploy (_model) .to ('sqlite::memory:')
|
||||
|
||||
@@ -1,9 +1,48 @@
|
||||
const cds = require('@sap/cds/lib')
|
||||
const { GET, expect } = cds.test ('@capire/bookshop')
|
||||
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
|
||||
const { GET, expect, axios } = cds.test ('@capire/bookshop')
|
||||
axios.defaults.auth = { username: 'alice', password: 'admin' }
|
||||
|
||||
describe('OData Protocol', () => {
|
||||
describe('cap/samples - Bookshop APIs', () => {
|
||||
|
||||
// Genres
|
||||
const Drama = {
|
||||
"name": "Drama",
|
||||
"descr": null,
|
||||
"ID": 11,
|
||||
"parent_ID": 10
|
||||
}
|
||||
const Mystery = {
|
||||
"name": "Mystery",
|
||||
"descr": null,
|
||||
"ID": 16,
|
||||
"parent_ID": 10
|
||||
}
|
||||
const Fantasy = {
|
||||
"name": "Fantasy",
|
||||
"descr": null,
|
||||
"ID": 13,
|
||||
"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 () => {
|
||||
@@ -17,6 +56,16 @@ describe('OData Protocol', () => {
|
||||
expect(data).to.contain('<Annotation Term="Common.Label" String="Currency"/>')
|
||||
})
|
||||
|
||||
it('serves ListOfBooks?$expand=genre,currency', async () => {
|
||||
const { data } = await GET `/browse/ListOfBooks ${{
|
||||
params: { $search: 'Po', $select: `title,author`, $expand:`genre,currency` },
|
||||
}}`
|
||||
expect(data.value).to.eql([
|
||||
{ ID: 251, title: 'The Raven', author: 'Edgar Allen Poe', genre:Mystery, currency:USD },
|
||||
{ ID: 252, title: 'Eleonora', author: 'Edgar Allen Poe', genre:Mystery, currency:USD },
|
||||
])
|
||||
})
|
||||
|
||||
it('supports $search in multiple fields', async () => {
|
||||
const { data } = await GET `/browse/Books ${{
|
||||
params: { $search: 'Po', $select: `title,author` },
|
||||
@@ -75,4 +124,16 @@ describe('OData Protocol', () => {
|
||||
{ ID: 271, title: 'Catweazle' },
|
||||
])
|
||||
})
|
||||
|
||||
it('serves user info', async () => {
|
||||
{
|
||||
const { data } = await GET (`/user/me`)
|
||||
expect(data).to.containSubset({ id: 'alice', locale:'en', tenant: null })
|
||||
}
|
||||
{
|
||||
const { data } = await GET (`/user/me`, {auth: { username: 'joe' }})
|
||||
expect(data).to.containSubset({ id: 'joe', locale:'en', tenant: null })
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@ const { resolve } = require('path')
|
||||
const verbose = process.env.CDS_TEST_VERBOSE
|
||||
// ||true
|
||||
|
||||
describe('Local NPM registry', () => {
|
||||
describe('cap/samples - Local NPM registry', () => {
|
||||
let registry
|
||||
let axios
|
||||
const cwd = resolve(__dirname, '..')
|
||||
@@ -20,7 +20,7 @@ describe('Local NPM registry', () => {
|
||||
|
||||
after(() => { registry.kill() })
|
||||
|
||||
for (const mod of ['bookshop','fiori','orders','reviews']) {
|
||||
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:{}})
|
||||
|
||||
Reference in New Issue
Block a user