mirror of
https://github.com/NationalSecurityAgency/skills-client.git
synced 2026-11-07 14:06:36 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca3de11171 | ||
|
|
cd997f6d5b | ||
|
|
54a54a5b00 | ||
|
|
c2f4df8afb | ||
|
|
4e4334a424 | ||
|
|
615a8db2d1 | ||
|
|
3ba071ac00 | ||
|
|
1dcc6bd29e | ||
|
|
386c634a3f | ||
|
|
f25bfb6252 | ||
|
|
1bb162bbd3 | ||
|
|
7e37d927ec | ||
|
|
9a488b0bc3 | ||
|
|
f2ca470d3f | ||
|
|
2ab9b7086c | ||
|
|
7b76ff01af | ||
|
|
8e4e2e4948 | ||
|
|
634e82d24e | ||
|
|
5544723938 | ||
|
|
72144d7734 | ||
|
|
8af1f62bd6 | ||
|
|
10c24e9bd7 | ||
|
|
38b0b502c3 | ||
|
|
563f9977b0 | ||
|
|
b78d329faa | ||
|
|
a777500389 | ||
|
|
c57c9d695f | ||
|
|
d866ce27db | ||
|
|
edb1c05d27 | ||
|
|
3d9e8c2571 | ||
|
|
843145e436 | ||
|
|
8a4fededb3 | ||
|
|
5325af1973 | ||
|
|
ed1238795c | ||
|
|
410a5fc740 | ||
|
|
b72d51c9ac | ||
|
|
1979f74084 | ||
|
|
76f1481557 | ||
|
|
af274ee955 | ||
|
|
e8e63fb4ef | ||
|
|
95a25b8f32 | ||
|
|
ba8194f6f9 | ||
|
|
40a6980846 | ||
|
|
44cd320c20 | ||
|
|
4e1eed3858 | ||
|
|
8173a7d564 | ||
|
|
4dd5e215b0 | ||
|
|
775cbff377 | ||
|
|
d58e9032a1 | ||
|
|
6c38e8f881 | ||
|
|
a67e38fa84 | ||
|
|
c23212f924 | ||
|
|
605356e400 | ||
|
|
2ad5fe410a | ||
|
|
f729048742 | ||
|
|
d27c5b28e2 | ||
|
|
570e7ddfa9 | ||
|
|
831c1c4209 | ||
|
|
eb23dc48d6 | ||
|
|
70372c52f9 | ||
|
|
e9f045a32a | ||
|
|
8954aba225 | ||
|
|
208af5c2ba | ||
|
|
36612b526e | ||
|
|
ca330f78ab | ||
|
|
4803c5181e | ||
|
|
3d2184ea4e | ||
|
|
9be1962510 | ||
|
|
23704d3171 | ||
|
|
b214a14669 | ||
|
|
a8f28f596b | ||
|
|
f93426c6ac | ||
|
|
0905b5b2b9 | ||
|
|
692d02cb5f | ||
|
|
58be278dd9 | ||
|
|
1ee43ef218 | ||
|
|
63af6a8bff | ||
|
|
fc4bf72202 | ||
|
|
085cf72470 | ||
|
|
e770f59643 | ||
|
|
4394a28fb8 | ||
|
|
51bdfb4ead | ||
|
|
e12308b801 | ||
|
|
18b1ba3a58 | ||
|
|
3fd50e096a | ||
|
|
51643e043e | ||
|
|
41ad8f9214 | ||
|
|
b94dec07fe | ||
|
|
4219fcdc97 | ||
|
|
e00e41651c | ||
|
|
5236d4a386 | ||
|
|
525adddfbf | ||
|
|
01cfcf68af | ||
|
|
da68860c7c | ||
|
|
c7da2e3759 | ||
|
|
473aeaa902 | ||
|
|
58c919b6f9 | ||
|
|
fda0db88bf | ||
|
|
07cdfb7421 | ||
|
|
a2d8a61ae9 | ||
|
|
6bed3b43a2 | ||
|
|
61f60feb39 | ||
|
|
c02439d325 | ||
|
|
88cb2f4b21 | ||
|
|
bdeb251c25 | ||
|
|
0a04cf2d69 | ||
|
|
45334d0c04 | ||
|
|
df6735fa76 | ||
|
|
8ac4afe087 | ||
|
|
9c4a47fa8f | ||
|
|
5d365d695b | ||
|
|
5ac40b6339 | ||
|
|
181b4096af | ||
|
|
e888279fe5 | ||
|
|
80d70d1532 | ||
|
|
2eb4ef60a4 | ||
|
|
3de3035185 | ||
|
|
2cc86d7b78 | ||
|
|
71f443e840 | ||
|
|
4abed70e49 | ||
|
|
8491bfddae | ||
|
|
ce83b210dd | ||
|
|
1ec8a224a8 | ||
|
|
df92e366b6 | ||
|
|
8c5c76f1f0 | ||
|
|
6e36163712 | ||
|
|
6af5c1a932 |
No files matched your search
@@ -5,6 +5,7 @@ name: Continuous Integration with OAuth
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 7 * * *'
|
||||
workflow_dispatch:
|
||||
#on:
|
||||
# push:
|
||||
# paths-ignore:
|
||||
|
||||
@@ -13,6 +13,7 @@ on:
|
||||
- 'README.md'
|
||||
- .github/workflows/skills-service-backward-compat.yml
|
||||
- .github/workflows/client-libs-backward-compat.yml
|
||||
workflow_dispatch:
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
|
||||
@@ -12,6 +12,7 @@ name: Client Libs Backward Compatibility
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 5 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
|
||||
@@ -12,6 +12,7 @@ name: Skills-service Backward Compatibility
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 6 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>3.1.1-SNAPSHOT</version>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
|
||||
@@ -32,10 +32,12 @@ limitations under the License.
|
||||
<script type="text/javascript">
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const isSummaryOnly = params.get('isSummaryOnly') ? JSON.parse(params.get('isSummaryOnly')) : false;
|
||||
const internalBackButton = params.get('internalBackButton') ? JSON.parse(params.get('internalBackButton')) : false;
|
||||
|
||||
const options = {
|
||||
autoScrollStrategy: 'top-of-page',
|
||||
isSummaryOnly,
|
||||
internalBackButton,
|
||||
};
|
||||
const themes = {
|
||||
default: {
|
||||
@@ -85,6 +87,12 @@ limitations under the License.
|
||||
window.location.search = params;
|
||||
};
|
||||
|
||||
const setInternalBackButton = () => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
params.set('internalBackButton', !options.internalBackButton);
|
||||
window.location.search = params;
|
||||
}
|
||||
|
||||
const getTheme = () => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
let themeName = params.get('themeName') ? params.get('themeName') : 'Bright (default)';
|
||||
@@ -98,6 +106,9 @@ limitations under the License.
|
||||
return version;
|
||||
};
|
||||
|
||||
const handleRouteChanged = (newPath) => {
|
||||
document.querySelector('#skillsDisplayPath').innerHTML = `Skills Display Path: [${newPath}]`;
|
||||
};
|
||||
axios.get("/api/config")
|
||||
.then((result) => {
|
||||
SkillsClient.SkillsConfiguration.configure(result.data);
|
||||
@@ -120,6 +131,7 @@ limitations under the License.
|
||||
options,
|
||||
version: getVersion(),
|
||||
theme: theme.theme,
|
||||
handleRouteChanged: handleRouteChanged,
|
||||
});
|
||||
clientDisplay.attachTo(document.querySelector('#skills-client-display'));
|
||||
};
|
||||
@@ -143,10 +155,10 @@ limitations under the License.
|
||||
|
||||
<ul class="navbar-nav flex-row mr-auto">
|
||||
<li class="nav-item pr-3">
|
||||
<a class="nav-link" href="index.html">Report Skill Events</a>
|
||||
<a class="nav-link" href="index.html" data-cy="reportSkillsLink">Report Skill Events</a>
|
||||
</li>
|
||||
<li class="nav-item active pr-3">
|
||||
<a class="nav-link" href="javascript:void(0)">User Display</a>
|
||||
<a class="nav-link" href="javascript:void(0)" data-cy="userDisplayLink">User Display</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -169,7 +181,13 @@ limitations under the License.
|
||||
<input type="checkbox" class="custom-control-input" id="displayTypeControl" onclick="setDisplayType()" checked>
|
||||
<label class="custom-control-label" for="displayTypeControl">Summary Only</label>
|
||||
</div>
|
||||
|
||||
<div class="d-inline custom-control custom-checkbox mx-2">
|
||||
<input type="checkbox" class="custom-control-input" id="internalBackButtonControl" onclick="setInternalBackButton()" checked>
|
||||
<label class="custom-control-label" for="internalBackButtonControl">Internal Back Button</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span id="skillsDisplayPath" data-cy="skillsDisplayPath"></span>
|
||||
</div>
|
||||
<div
|
||||
style="min-height: 860px">
|
||||
@@ -192,4 +210,5 @@ limitations under the License.
|
||||
|
||||
<script type="text/javascript">
|
||||
document.getElementById("displayTypeControl").checked = isSummaryOnly;
|
||||
document.getElementById("internalBackButtonControl").checked = internalBackButton;
|
||||
</script>
|
||||
@@ -60,10 +60,10 @@ limitations under the License.
|
||||
|
||||
<ul class="navbar-nav flex-row mr-auto">
|
||||
<li class="nav-item pr-3">
|
||||
<a class="nav-link" href="index.html">Report Skill Events</a>
|
||||
<a class="nav-link" href="index.html" data-cy="reportSkillsLink">Report Skill Events</a>
|
||||
</li>
|
||||
<li class="nav-item active pr-3">
|
||||
<a class="nav-link" href="javascript:void(0)">User Display</a>
|
||||
<a class="nav-link" href="javascript:void(0)" data-cy="userDisplayLink">User Display</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -72,10 +72,10 @@ limitations under the License.
|
||||
|
||||
<ul class="navbar-nav flex-row mr-auto">
|
||||
<li class="nav-item active pr-3">
|
||||
<a class="nav-link" href="javascript:void(0)">Report Skill Events</a>
|
||||
<a class="nav-link" href="javascript:void(0)" data-cy="reportSkillsLink">Report Skill Events</a>
|
||||
</li>
|
||||
<li class="nav-item pr-3">
|
||||
<a class="nav-link" href="clientDisplay.html">User Display</a>
|
||||
<a class="nav-link" href="clientDisplay.html" data-cy="userDisplayLink">User Display</a>
|
||||
</li>
|
||||
</ul>
|
||||
<button type="button" class="btn btn-primary">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "skills-int-client-js",
|
||||
"version": "3.1.1",
|
||||
"version": "3.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib Integration Tests - Native JS",
|
||||
"main": "index.js",
|
||||
@@ -16,7 +16,7 @@
|
||||
},
|
||||
"author": "SkillTree Team",
|
||||
"dependencies": {
|
||||
"@skilltree/skills-client-js": "3.1.1",
|
||||
"@skilltree/skills-client-js": "3.3.0",
|
||||
"axios": "^0.21.1",
|
||||
"bootstrap": "4.5.2",
|
||||
"jquery": "^3.5.1",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<version>3.1.1-SNAPSHOT</version>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skills-int-client-js</artifactId>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "skills-int-client-ng",
|
||||
"version": "3.1.1",
|
||||
"version": "3.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib - Angular",
|
||||
"author": "SkillTree Team",
|
||||
@@ -28,7 +28,7 @@
|
||||
"@angular/platform-browser-dynamic": "10.1.5",
|
||||
"@angular/router": "10.0.14",
|
||||
"@ng-bootstrap/ng-bootstrap": "7.0.0",
|
||||
"@skilltree/skills-client-ng": "3.1.1",
|
||||
"@skilltree/skills-client-ng": "3.3.0",
|
||||
"@types/js-beautify": "1.11.0",
|
||||
"axios": "0.21.1",
|
||||
"bootstrap": "4.5.3",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<version>3.1.1-SNAPSHOT</version>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skills-int-client-ng</artifactId>
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { HighlightModule } from 'ngx-highlightjs';
|
||||
import { HighlightModule, HIGHLIGHT_OPTIONS } from 'ngx-highlightjs';
|
||||
import { SkillsLevelModule, SkillsDisplayModule, SkilltreeModule } from '@skilltree/skills-client-ng'
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
@@ -58,7 +58,15 @@ import { PlaceholderDirective } from './directives/placeholder.directive';
|
||||
{ path: '', component: ReportSkillsComponent },
|
||||
])
|
||||
],
|
||||
providers: [ExampleService],
|
||||
providers: [
|
||||
ExampleService,
|
||||
{
|
||||
provide: HIGHLIGHT_OPTIONS,
|
||||
useValue: {
|
||||
fullLibraryLoader: () => import('highlight.js'),
|
||||
}
|
||||
}
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
+12
-3
@@ -30,11 +30,20 @@ limitations under the License.
|
||||
<label class="custom-control-label" for="customSwitch1">Summary Only</label>
|
||||
</div>
|
||||
|
||||
<div class="custom-control custom-switch d-inline-block ml-3 border-right pr-2">
|
||||
<input type="checkbox" class="custom-control-input" id="customSwitch2" (click)="setInternalBackButtonUrlParam()"
|
||||
[checked]="displayOptions.internalBackButton">
|
||||
<label class="custom-control-label" for="customSwitch2">Internal Back Button</label>
|
||||
</div>
|
||||
|
||||
<a href="javascript:void(0)" class="ml-2" (click)="scrollTo('sample-code')">Show Source</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span id="skillsDisplayPath" data-cy="skillsDisplayPath">Skills Display Path: [{{ skillsDisplayRoutePath }}]</span>
|
||||
</div>
|
||||
|
||||
<div class="border rounded">
|
||||
<skills-display *ngIf="selectedTheme" [options]="displayOptions" [version]="version" [theme]="selectedTheme.theme">
|
||||
<skills-display *ngIf="selectedTheme" [options]="displayOptions" [version]="version" [theme]="selectedTheme.theme" [handleRouteChanged]="skillsDisplayRouteChanged">
|
||||
</skills-display>
|
||||
</div>
|
||||
|
||||
@@ -51,4 +60,4 @@ limitations under the License.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
+12
-1
@@ -31,6 +31,7 @@ export class SkillsDisplayComponent implements OnInit {
|
||||
selectedTheme: any;
|
||||
themes: Array<any> = themes;
|
||||
showSampleCode: boolean = false;
|
||||
skillsDisplayRoutePath: string = '/';
|
||||
|
||||
constructor(private route: ActivatedRoute, private router: Router, private viewportScroller: ViewportScroller) { }
|
||||
|
||||
@@ -40,6 +41,7 @@ export class SkillsDisplayComponent implements OnInit {
|
||||
this.displayOptions = {
|
||||
autoScrollStrategy: 'top-of-page',
|
||||
isSummaryOnly: params['isSummaryOnly'] ? JSON.parse(params['isSummaryOnly']) : false,
|
||||
internalBackButton: params['internalBackButton'] ? JSON.parse(params['internalBackButton']) : false,
|
||||
};
|
||||
this.selectedTheme = params['themeName'] ? this.findTheme(params['themeName']) : this.themes[0];
|
||||
});
|
||||
@@ -49,6 +51,10 @@ export class SkillsDisplayComponent implements OnInit {
|
||||
return this.themes.find((item) => item.name === name);
|
||||
}
|
||||
|
||||
skillsDisplayRouteChanged = (newPath: string) => {
|
||||
this.skillsDisplayRoutePath = newPath;
|
||||
}
|
||||
|
||||
refreshPage() {
|
||||
setTimeout(() => {
|
||||
document.location.reload();
|
||||
@@ -66,6 +72,11 @@ export class SkillsDisplayComponent implements OnInit {
|
||||
this.refreshPage();
|
||||
}
|
||||
|
||||
setInternalBackButtonUrlParam() {
|
||||
this.displayOptions.internalBackButton = !this.displayOptions.internalBackButton;
|
||||
this.router.navigate(['angular/showSkills'], { queryParams: { internalBackButton: this.displayOptions.internalBackButton }, queryParamsHandling: 'merge' });
|
||||
this.refreshPage();
|
||||
}
|
||||
scrollTo(elementId: string) {
|
||||
this.showSampleCode = true;
|
||||
setTimeout(() => {
|
||||
@@ -77,7 +88,7 @@ export class SkillsDisplayComponent implements OnInit {
|
||||
let sampleCode = `
|
||||
<template>
|
||||
<skills-level /> <!-- You can display the user's current Level using the SkillsLevel component -->
|
||||
<skills-display :theme="selectedTheme" ${this.displayOptions.isSummaryOnly ? ':options="displayOptions"' : ''}/>
|
||||
<skills-display :theme="selectedTheme" ${(this.displayOptions.isSummaryOnly || this.displayOptions.internalBackButton) ? ':options="displayOptions"' : ''}/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"name": "skills-int-client-react",
|
||||
"version": "3.1.1",
|
||||
"version": "3.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib Integration Tests - React",
|
||||
"homepage": "/react/",
|
||||
"dependencies": {
|
||||
"@skilltree/skills-client-react": "3.1.1",
|
||||
"@skilltree/skills-client-react": "3.3.0",
|
||||
"axios": "0.21.1",
|
||||
"bootstrap": "4.5.3",
|
||||
"core-js": "3.6.5",
|
||||
"highlightjs": "9.16.2",
|
||||
"js-beautify": "1.13.0",
|
||||
"prop-types": "15.7.2",
|
||||
"react": "16.13.1",
|
||||
"react-bootstrap": "1.3.0",
|
||||
"react-dom": "16.13.1",
|
||||
"react-highlight": "0.12.0",
|
||||
"react-router": "5.2.0",
|
||||
"react-router-dom": "5.2.0",
|
||||
"prop-types": "15.7.2"
|
||||
"react-router-dom": "5.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"serve": "PORT=8083 react-scripts start",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<version>3.1.1-SNAPSHOT</version>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skills-int-client-react</artifactId>
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ const Navigation = () => {
|
||||
<Navbar.Collapse id="nav-collapse" is-nav="true">
|
||||
<Nav>
|
||||
<NavLink activeClassName="router-link-active" className="nav-link" to="/">Report Skill Events</NavLink>
|
||||
<NavLink activeClassName="router-link-active" className="nav-link" to="/showSkills">User Display</NavLink>
|
||||
<NavLink activeClassName="router-link-active" className="nav-link" to="/showSkills?isSummaryOnly=false&internalBackButton=false&themeName=Bright%20(default)&skillsVersion=">User Display</NavLink>
|
||||
</Nav>
|
||||
</Navbar.Collapse>
|
||||
<Button variant="primary">
|
||||
|
||||
@@ -32,6 +32,10 @@ const findTheme = (name) => {
|
||||
|
||||
const scrollToRef = (ref) => window.scrollTo(0, ref.current.offsetTop);
|
||||
|
||||
const handleRouteChanged = (newPath) => {
|
||||
document.querySelector('#skillsDisplayPath').innerHTML = `Skills Display Path: [${newPath}]`;
|
||||
};
|
||||
|
||||
function usePrevious(value){
|
||||
const ref = React.useRef();
|
||||
React.useEffect(() => {
|
||||
@@ -63,6 +67,15 @@ const ShowSkill = () => {
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const [internalBackButton, setInternalBackButton] = React.useState(() => {
|
||||
const urlInternalBackButton = getUrlParam('internalBackButton');
|
||||
if ( urlInternalBackButton ) {
|
||||
return JSON.parse(urlInternalBackButton)
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const [skillsVersion] = React.useState(() => {
|
||||
const skillsVersion = getUrlParam("skillsVersion");
|
||||
if(skillsVersion) {
|
||||
@@ -71,9 +84,10 @@ const ShowSkill = () => {
|
||||
return '';
|
||||
});
|
||||
|
||||
const [options, setOptions] = React.useState({ isSummaryOnly: isSummaryOnly, autoScrollStrategy: 'top-offset', scrollTopOffset: 110 });
|
||||
const [options, setOptions] = React.useState({ isSummaryOnly: isSummaryOnly, internalBackButton: internalBackButton, autoScrollStrategy: 'top-offset', scrollTopOffset: 110 });
|
||||
|
||||
const previousIsSummaryOnly = usePrevious(isSummaryOnly);
|
||||
const previousInternalBackButton = usePrevious(internalBackButton);
|
||||
const previousSelectedTheme = usePrevious(selectedTheme);
|
||||
const previousSkillsVersion = usePrevious(skillsVersion);
|
||||
|
||||
@@ -84,14 +98,14 @@ const ShowSkill = () => {
|
||||
params+=`${key}=${paramsObj[key]}&`;
|
||||
});
|
||||
params = params.replace(/&$/,'');
|
||||
history.push({pathname:history.location.pathname, search: params});
|
||||
history.replace({pathname:history.location.pathname, search: params});
|
||||
};
|
||||
|
||||
if (isSummaryOnly !== previousIsSummaryOnly || selectedTheme !== previousSelectedTheme) {
|
||||
saveUrlParam({'isSummaryOnly': isSummaryOnly, 'themeName': selectedTheme.name, 'skillsVersion': skillsVersion});
|
||||
if (isSummaryOnly !== previousIsSummaryOnly || internalBackButton !== previousInternalBackButton || selectedTheme !== previousSelectedTheme) {
|
||||
saveUrlParam({'isSummaryOnly': isSummaryOnly, 'internalBackButton': internalBackButton, 'themeName': selectedTheme.name, 'skillsVersion': skillsVersion});
|
||||
}
|
||||
|
||||
}, [isSummaryOnly, selectedTheme, skillsVersion, previousIsSummaryOnly, previousSelectedTheme, previousSkillsVersion, history]);
|
||||
}, [isSummaryOnly, internalBackButton, selectedTheme, skillsVersion, previousIsSummaryOnly, previousInternalBackButton, previousSelectedTheme, previousSkillsVersion, history]);
|
||||
|
||||
const sampleCodeRef = React.createRef();
|
||||
const executeScroll = () => scrollToRef(sampleCodeRef);
|
||||
@@ -121,12 +135,18 @@ const ShowSkill = () => {
|
||||
</DropdownButton>
|
||||
<Button variant={isSummaryOnly ? 'primary' : 'outline-primary'}
|
||||
onClick={() => { setIsSummaryOnly(!isSummaryOnly);
|
||||
setOptions({isSummaryOnly:!isSummaryOnly,autoScrollStrategy: 'top-offset', scrollTopOffset: 110}) }}>Summary Only</Button>
|
||||
setOptions({isSummaryOnly:!isSummaryOnly,internalBackButton:internalBackButton,autoScrollStrategy: 'top-offset', scrollTopOffset: 110}) }}>Summary Only</Button>
|
||||
|
||||
<Button variant={internalBackButton ? 'primary' : 'outline-primary'}
|
||||
onClick={() => { setInternalBackButton(!internalBackButton);
|
||||
setOptions({isSummaryOnly:isSummaryOnly,internalBackButton:!internalBackButton,autoScrollStrategy: 'top-offset', scrollTopOffset: 110}) }}>Internal Back Button</Button>
|
||||
<Button variant="link" onClick={executeScroll}>Show Source</Button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span id="skillsDisplayPath" data-cy="skillsDisplayPath"></span>
|
||||
</div>
|
||||
<div className="border rounded">
|
||||
<SkillsDisplay options={options} theme={selectedTheme.theme} version={skillsVersion}/>
|
||||
<SkillsDisplay options={options} theme={selectedTheme.theme} version={skillsVersion} handleRouteChanged={handleRouteChanged}/>
|
||||
</div>
|
||||
|
||||
<div ref={sampleCodeRef}>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "skills-int-client-vue",
|
||||
"version": "3.1.1",
|
||||
"version": "3.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib Integration Tests - Vue",
|
||||
"scripts": {
|
||||
@@ -14,7 +14,7 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@skilltree/skills-client-vue": "3.1.1",
|
||||
"@skilltree/skills-client-vue": "3.3.0",
|
||||
"axios": "0.21.1",
|
||||
"bootstrap": "4.5.3",
|
||||
"bootstrap-vue": "2.17.3",
|
||||
@@ -29,11 +29,11 @@
|
||||
"vuex": "3.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "4.5.7",
|
||||
"@vue/cli-plugin-eslint": "4.5.7",
|
||||
"@vue/cli-service": "4.5.7",
|
||||
"@vue/cli-plugin-babel": "4.5.13",
|
||||
"@vue/cli-plugin-eslint": "4.5.13",
|
||||
"@vue/cli-service": "4.5.13",
|
||||
"babel-eslint": "10.1.0",
|
||||
"eslint": "7.11.0",
|
||||
"eslint": "6.2.0",
|
||||
"eslint-plugin-vue": "7.0.1",
|
||||
"license-check-and-add": "3.0.4",
|
||||
"license-checker": "25.0.1",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<version>3.1.1-SNAPSHOT</version>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skills-int-client-vue</artifactId>
|
||||
|
||||
|
||||
+5
-2
@@ -107,8 +107,11 @@ limitations under the License.
|
||||
},
|
||||
data() {
|
||||
const existingAuthenticator = SkillsConfiguration.getAuthenticator();
|
||||
const authenticator = existingAuthenticator.replace(/\/users\/user1/, '/users/proj2/user2')
|
||||
const projectId = "proj2"
|
||||
const projectId = this.$store.state.proxiedProjectId;
|
||||
const proxiedUser = this.$store.state.proxiedUserId;
|
||||
const replaceRegex = /users\/[^/]+\/token/;
|
||||
|
||||
const authenticator = existingAuthenticator.replace(replaceRegex, `users/${projectId}/${proxiedUser}/token`);
|
||||
return {
|
||||
token: '',
|
||||
version: this.$route.query.skillsVersion ? JSON.parse(this.$route.query.skillsVersion) : 1000,
|
||||
|
||||
+33
-2
@@ -34,6 +34,11 @@ limitations under the License.
|
||||
switch>
|
||||
Summary Only
|
||||
</b-form-checkbox>
|
||||
<b-form-checkbox class="d-inline-block ml-3 border-right pr-2"
|
||||
v-model="displayOptions.internalBackButton"
|
||||
switch>
|
||||
Internal Back Button
|
||||
</b-form-checkbox>
|
||||
|
||||
<b-link
|
||||
class="ml-2"
|
||||
@@ -41,12 +46,17 @@ limitations under the License.
|
||||
v-scroll-to="'#sample-code'"
|
||||
@click="showSampleCode = true">Show Source</b-link>
|
||||
</div>
|
||||
<div>
|
||||
<span id="skillsDisplayPath" data-cy="skillsDisplayPath">Skills Display Path: [{{skillsDisplayPath}}]</span>
|
||||
</div>
|
||||
<div class="border rounded">
|
||||
<skills-display
|
||||
v-if="selectedTheme"
|
||||
:options="displayOptions"
|
||||
:version="version"
|
||||
:theme="selectedTheme.theme"/>
|
||||
:theme="selectedTheme.theme"
|
||||
@route-changed="skillsDisplayRouteChanged"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedTheme && showSampleCode"
|
||||
@@ -112,8 +122,10 @@ limitations under the License.
|
||||
displayOptions: {
|
||||
autoScrollStrategy: 'top-of-page',
|
||||
isSummaryOnly: this.$route.query.isSummaryOnly ? JSON.parse(this.$route.query.isSummaryOnly) : false,
|
||||
internalBackButton: this.$route.query.internalBackButton ? JSON.parse(this.$route.query.internalBackButton) : false,
|
||||
},
|
||||
showSampleCode: false,
|
||||
skillsDisplayPath: '',
|
||||
themes: this.getThemes(),
|
||||
selectedTheme: this.$route.query.themeName ? this.findTheme(this.$route.query.themeName) : this.getThemes()[0],
|
||||
};
|
||||
@@ -138,6 +150,9 @@ limitations under the License.
|
||||
'displayOptions.isSummaryOnly'() {
|
||||
this.setIsSummaryOnlyUrlParam();
|
||||
},
|
||||
'displayOptions.internalBackButton'() {
|
||||
this.setInternalBackButtonUrlParam();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getThemes() {
|
||||
@@ -159,7 +174,19 @@ limitations under the License.
|
||||
this.$router.push({
|
||||
query: {
|
||||
themeName: this.selectedTheme.name,
|
||||
isSummaryOnly: this.displayOptions.isSummaryOnly
|
||||
isSummaryOnly: this.displayOptions.isSummaryOnly,
|
||||
internalBackButton: this.displayOptions.internalBackButton,
|
||||
}
|
||||
});
|
||||
this.refreshPage();
|
||||
},
|
||||
|
||||
setInternalBackButtonUrlParam() {
|
||||
this.$router.push({
|
||||
query: {
|
||||
themeName: this.selectedTheme.name,
|
||||
isSummaryOnly: this.displayOptions.isSummaryOnly,
|
||||
internalBackButton: this.displayOptions.internalBackButton,
|
||||
}
|
||||
});
|
||||
this.refreshPage();
|
||||
@@ -169,6 +196,10 @@ limitations under the License.
|
||||
return this.getThemes().find((item) => item.name === name);
|
||||
|
||||
},
|
||||
|
||||
skillsDisplayRouteChanged(newPath) {
|
||||
this.skillsDisplayPath = newPath;
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -21,6 +21,7 @@ import router from './router';
|
||||
import axios from 'axios';
|
||||
import { SkillsDirective, SkillsConfiguration, Logger } from '@skilltree/skills-client-vue';
|
||||
import VueHighlightJS from 'vue-highlightjs'
|
||||
import store from './store';
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
@@ -33,15 +34,23 @@ Vue.use(VueHighlightJS)
|
||||
axios.get("/api/config")
|
||||
.then((result) => {
|
||||
SkillsConfiguration.configure(result.data);
|
||||
SkillsConfiguration.configure(result.data);
|
||||
SkillsConfiguration.configure(result.data);
|
||||
store.commit('projectId', result.data.projectId);
|
||||
store.commit('authenticator', result.data.authenticator);
|
||||
store.commit('proxiedUserId', result.data.proxiedUserId);
|
||||
store.commit('proxiedProjectId', result.data.proxiedProjectId);
|
||||
})
|
||||
.then(() => {
|
||||
SkillsConfiguration.afterConfigure().then(() => {
|
||||
console.log('afterConfigure() - this should only be called once!');
|
||||
if (window.Cypress) {
|
||||
window.skillsLogger = Logger;
|
||||
}
|
||||
new Vue({
|
||||
render: h => h(App),
|
||||
router,
|
||||
store,
|
||||
}).$mount('#app');
|
||||
})
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2020 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
projectId: '',
|
||||
authenticator: '',
|
||||
proxiedUserId: '',
|
||||
proxiedProjectId: '',
|
||||
},
|
||||
mutations: {
|
||||
projectId(state, projectId) {
|
||||
state.projectId = projectId;
|
||||
},
|
||||
authenticator(state, projectSearch) {
|
||||
state.projectSearch = projectSearch;
|
||||
},
|
||||
proxiedUserId(state, proxiedUserId) {
|
||||
state.proxiedUserId = proxiedUserId;
|
||||
},
|
||||
proxiedProjectId(state, proxiedProjectId) {
|
||||
state.proxiedProjectId = proxiedProjectId;
|
||||
}
|
||||
},
|
||||
});
|
||||
+178
-72
@@ -19,6 +19,10 @@ const homePage = '/angular/reportSkills'
|
||||
|
||||
context('Angular Tests', () => {
|
||||
|
||||
const laterThan_1_4_0 = Utils.skillsServiceVersionLaterThan('1.4.0');
|
||||
const missingSkillErrorCode = laterThan_1_4_0 ? 404 : 400;
|
||||
const noThemeBackground = laterThan_1_4_0 ? 'rgba(0, 0, 0, 0)' : 'rgb(255, 255, 255)';
|
||||
|
||||
it('level component should be reactive', () => {
|
||||
cy.createDefaultProject()
|
||||
const sendEventViaDropdownId = '#PureJSReportAnySkill';
|
||||
@@ -159,16 +163,15 @@ context('Angular Tests', () => {
|
||||
it('skilltree directive on click', () => {
|
||||
cy.createDefaultProject(1, 2, 50, 2)
|
||||
|
||||
cy.server().route('POST', '/api/projects/proj1/skills/IronMan').as('postSkill')
|
||||
cy.intercept('POST', '/api/projects/proj1/skills/IronMan').as('postSkill')
|
||||
|
||||
cy.visitHomePage(homePage);
|
||||
|
||||
Cypress.Commands.add("clickOnDirectiveBtn", (skillApplied = true) => {
|
||||
cy.get('#SkillsDirectiveClickEvent button').click()
|
||||
cy.wait('@postSkill')
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
expect(xhr.status).to.eq(200)
|
||||
expect(xhr.responseBody).to.have.property('skillApplied').to.eq(skillApplied)
|
||||
cy.wait('@postSkill').then((intercept) => {
|
||||
expect(intercept.response.statusCode).to.eq(200)
|
||||
expect(intercept.response.body).to.have.property('skillApplied').to.eq(skillApplied)
|
||||
});
|
||||
})
|
||||
|
||||
@@ -180,16 +183,15 @@ context('Angular Tests', () => {
|
||||
|
||||
it('skilltree directive on input', () => {
|
||||
cy.createDefaultProject(1, 2, 50, 2)
|
||||
cy.server().route('POST', '/api/projects/proj1/skills/Thor').as('postSkill')
|
||||
cy.intercept('POST', '/api/projects/proj1/skills/Thor').as('postSkill')
|
||||
|
||||
cy.visitHomePage(homePage);
|
||||
|
||||
Cypress.Commands.add("typeToInput", (skillApplied = true) => {
|
||||
cy.get('#SkillsDirectiveInputEvent input').type('h')
|
||||
cy.wait('@postSkill')
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
expect(xhr.status).to.eq(200)
|
||||
expect(xhr.responseBody).to.have.property('skillApplied').to.eq(skillApplied)
|
||||
cy.wait('@postSkill').then((intercept) => {
|
||||
expect(intercept.response.statusCode).to.eq(200)
|
||||
expect(intercept.response.body).to.have.property('skillApplied').to.eq(skillApplied)
|
||||
});
|
||||
})
|
||||
|
||||
@@ -200,106 +202,93 @@ context('Angular Tests', () => {
|
||||
|
||||
it('skilltree directive on click with error', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route('POST', '/api/projects/proj1/skills/DoesNotExist').as('postSkill')
|
||||
cy.intercept('POST', '/api/projects/proj1/skills/DoesNotExist').as('postSkill')
|
||||
|
||||
cy.visitHomePage(homePage);
|
||||
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
expect(xhr.status).to.eq(400)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
cy.wait('@postSkill').then((intercept) => {
|
||||
expect(intercept.response.statusCode).to.eq(missingSkillErrorCode)
|
||||
expect(intercept.response.body).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
|
||||
it('skilltree directive on input with error', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route('POST', '/api/projects/proj1/skills/DoesNotExist').as('postSkill')
|
||||
cy.intercept('POST', '/api/projects/proj1/skills/DoesNotExist').as('postSkill')
|
||||
|
||||
cy.visitHomePage(homePage);
|
||||
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
expect(xhr.status).to.eq(400)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
cy.wait('@postSkill').then((intercept) => {
|
||||
expect(intercept.response.statusCode).to.eq(missingSkillErrorCode)
|
||||
expect(intercept.response.body).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
|
||||
it('skill display', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/angular/showSkills')
|
||||
cy.wait('@getToken')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('My Level')
|
||||
cy.wrapIframe().contains('50 Points earned Today')
|
||||
cy.wrapIframe().contains('Subject 0')
|
||||
cy.clientDisplay(true).contains('My Level')
|
||||
cy.clientDisplay().contains('50 Points earned Today')
|
||||
cy.clientDisplay().contains('Subject 0')
|
||||
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
cy.clientDisplay().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', noThemeBackground);
|
||||
})
|
||||
|
||||
it('skill display - summary only', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/angular/showSkills?isSummaryOnly=true')
|
||||
cy.wait('@getToken')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('My Level')
|
||||
cy.wrapIframe().contains('50 Points earned Today')
|
||||
cy.wrapIframe().contains('Subject 0').should('not.exist')
|
||||
cy.clientDisplay(true).contains('My Level')
|
||||
cy.clientDisplay().contains('50 Points earned Today')
|
||||
cy.clientDisplay().contains('Subject 0').should('not.exist')
|
||||
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
cy.clientDisplay().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', noThemeBackground);
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/angular/showSkills?themeName=Dark Blue')
|
||||
cy.wait('@getToken')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('My Level')
|
||||
cy.wrapIframe().contains('50 Points earned Today')
|
||||
cy.wrapIframe().contains('Subject 0')
|
||||
cy.clientDisplay(true).contains('My Level')
|
||||
cy.clientDisplay().contains('50 Points earned Today')
|
||||
cy.clientDisplay().contains('Subject 0')
|
||||
|
||||
// verify dark blue background of hex #152E4d
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
cy.clientDisplay().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(21, 46, 77)');
|
||||
})
|
||||
|
||||
it('skill display - summary only - theme', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/angular/showSkills?themeName=Dark Blue&isSummaryOnly=true')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('My Level')
|
||||
cy.wrapIframe().contains('50 Points earned Today')
|
||||
cy.wrapIframe().contains('Subject 0').should('not.exist')
|
||||
cy.clientDisplay(true).contains('My Level')
|
||||
cy.clientDisplay().contains('50 Points earned Today')
|
||||
cy.clientDisplay().contains('Subject 0').should('not.exist')
|
||||
|
||||
// verify dark blue background of hex #152E4d
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
cy.clientDisplay().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(21, 46, 77)');
|
||||
})
|
||||
|
||||
it('client display should display an error if skills service is down', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route({
|
||||
method: 'GET',
|
||||
url: '/public/status',
|
||||
status: 503, // server is down
|
||||
response: {}
|
||||
cy.intercept('/public/status',
|
||||
{
|
||||
statusCode: 503, // server is down
|
||||
body: {}
|
||||
}).as('getStatus')
|
||||
cy.visit('/angular/showSkills')
|
||||
cy.wait('@getStatus')
|
||||
@@ -309,39 +298,156 @@ context('Angular Tests', () => {
|
||||
|
||||
it('only display skills up-to the provided version', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendAddSkill('skillv1', 1)
|
||||
cy.backendAddSkill('skillv2', 2)
|
||||
|
||||
cy.visit('/angular/showSkills')
|
||||
cy.wait('@getToken')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('Earn up to 200 points')
|
||||
cy.clientDisplay(true).contains('Earn up to 200 points')
|
||||
|
||||
cy.visit('/angular/reportSkills')
|
||||
cy.get('#globalEventResultDiv').should('be.visible');
|
||||
|
||||
cy.visit('/angular/showSkills?skillsVersion=1')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('Earn up to 150 points')
|
||||
cy.clientDisplay().contains('Earn up to 150 points')
|
||||
|
||||
cy.visit('/angular/reportSkills')
|
||||
cy.get('#globalEventResultDiv').should('be.visible');
|
||||
|
||||
cy.visit('/angular/showSkills?skillsVersion=0')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('Earn up to 100 points')
|
||||
cy.clientDisplay().contains('Earn up to 100 points')
|
||||
});
|
||||
|
||||
it('skillsClientVersion is reported correctly', () => {
|
||||
cy.createDefaultProject()
|
||||
cy.intercept('POST', '/api/projects/proj1/skillsClientVersion', (req) => {
|
||||
expect(req.body).to.have.property('skillsClientVersion').and.to.contain('@skilltree/skills-client-ng-')
|
||||
req.reply((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
expect(res.body).to.have.property('success').to.eq(true)
|
||||
})
|
||||
}).as('reportClientVersion')
|
||||
|
||||
cy.visit(homePage)
|
||||
|
||||
cy.server().route('POST', '/api/projects/proj1/skillsClientVersion').as('reportClientVersion')
|
||||
|
||||
cy.wait('@reportClientVersion')
|
||||
cy.get('@reportClientVersion').then((xhr) => {
|
||||
expect(xhr.status).to.eq(200)
|
||||
expect(xhr.responseBody).to.have.property('success').to.eq(true)
|
||||
});
|
||||
cy.get('@reportClientVersion').should((xhr) => {
|
||||
expect(xhr.request.body, 'request body').to.have.property('skillsClientVersion').and.to.contain('@skilltree/skills-client-ng-')
|
||||
});
|
||||
})
|
||||
|
||||
if (Utils.skillsServiceVersionLaterThan('1.5.0')) {
|
||||
it('internal back button when when returning from an external page - multiple layers deep', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/angular/showSkills?internalBackButton=true');
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview that contains the back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('exist');
|
||||
|
||||
// click the back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.cdBack('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.cdBack('User Skills');
|
||||
});
|
||||
|
||||
it('browser back button works correctly when internal back button is not present', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/angular/showSkills?internalBackButton=false');
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
|
||||
// click the browser back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
});
|
||||
|
||||
it('deep link and reload', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// navigate to Rank Overview via direct link
|
||||
cy.visit('/angular/showSkills?skillsClientDisplayPath=%2Frank');
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
// reload and confirm we are still on Rank Overview page
|
||||
cy.reload();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
});
|
||||
|
||||
it('back button after reload', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/angular/showSkills?internalBackButton=false');
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
|
||||
cy.reload();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
// click the browser back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
});
|
||||
|
||||
it('route change is passed to the client app', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/angular/showSkills?internalBackButton=false');
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/]');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/subjects/subj0]');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/subjects/subj0/rank]');
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
@@ -18,6 +18,10 @@ import Utils from "./Utils";
|
||||
const homePage = '/native/index.html'
|
||||
|
||||
context("Native JS Tests", () => {
|
||||
|
||||
const laterThan_1_4_0 = Utils.skillsServiceVersionLaterThan('1.4.0');
|
||||
const noThemeBackground = laterThan_1_4_0 ? 'rgba(0, 0, 0, 0)' : 'rgb(255, 255, 255)';
|
||||
|
||||
it("global event show correct results", () => {
|
||||
cy.createDefaultProject();
|
||||
|
||||
@@ -100,8 +104,7 @@ context("Native JS Tests", () => {
|
||||
|
||||
it("skill display", () => {
|
||||
cy.createDefaultTinyProject();
|
||||
cy.server()
|
||||
.route(Cypress.env('tokenUrl'))
|
||||
cy.intercept(Cypress.env('tokenUrl'))
|
||||
.as("getToken");
|
||||
cy.backendPost("/api/projects/proj1/skills/Thor", {
|
||||
userId: Cypress.env('proxyUser'),
|
||||
@@ -116,13 +119,12 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
.should('have.css', 'background-color').and('equal', noThemeBackground);
|
||||
});
|
||||
|
||||
it("skill display - default options", () => {
|
||||
cy.createDefaultTinyProject();
|
||||
cy.server()
|
||||
.route(Cypress.env('tokenUrl'))
|
||||
cy.intercept(Cypress.env('tokenUrl'))
|
||||
.as("getToken");
|
||||
cy.backendPost("/api/projects/proj1/skills/Thor", {
|
||||
userId: Cypress.env('proxyUser'),
|
||||
@@ -138,13 +140,12 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
.should('have.css', 'background-color').and('equal', noThemeBackground);
|
||||
});
|
||||
|
||||
it("skill display - summary only", () => {
|
||||
cy.createDefaultTinyProject();
|
||||
cy.server()
|
||||
.route(Cypress.env('tokenUrl'))
|
||||
cy.intercept(Cypress.env('tokenUrl'))
|
||||
.as("getToken");
|
||||
cy.backendPost("/api/projects/proj1/skills/Thor", {
|
||||
userId: Cypress.env('proxyUser'),
|
||||
@@ -160,13 +161,12 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
.should('have.css', 'background-color').and('equal', noThemeBackground);
|
||||
});
|
||||
|
||||
it("skill display - theme", () => {
|
||||
cy.createDefaultTinyProject();
|
||||
cy.server()
|
||||
.route(Cypress.env('tokenUrl'))
|
||||
cy.intercept(Cypress.env('tokenUrl'))
|
||||
.as("getToken");
|
||||
cy.backendPost("/api/projects/proj1/skills/Thor", {
|
||||
userId: Cypress.env('proxyUser'),
|
||||
@@ -187,8 +187,7 @@ context("Native JS Tests", () => {
|
||||
|
||||
it("skill display - summary only - theme", () => {
|
||||
cy.createDefaultTinyProject();
|
||||
cy.server()
|
||||
.route(Cypress.env('tokenUrl'))
|
||||
cy.intercept(Cypress.env('tokenUrl'))
|
||||
.as("getToken");
|
||||
cy.backendPost("/api/projects/proj1/skills/Thor", {
|
||||
userId: Cypress.env('proxyUser'),
|
||||
@@ -208,18 +207,15 @@ context("Native JS Tests", () => {
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(21, 46, 77)');
|
||||
});
|
||||
|
||||
it("client display should display an error if skills service is down", () => {
|
||||
cy.createDefaultTinyProject();
|
||||
cy.server()
|
||||
.route({
|
||||
method: "GET",
|
||||
url: "/public/status",
|
||||
status: 503, // server is down
|
||||
response: {}
|
||||
})
|
||||
.as("getStatus");
|
||||
cy.visit("/native/clientDisplay.html");
|
||||
cy.wait("@getStatus");
|
||||
it('client display should display an error if skills service is down', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.intercept('/public/status',
|
||||
{
|
||||
statusCode: 503, // server is down
|
||||
body: {}
|
||||
}).as('getStatus')
|
||||
cy.visit('/native/clientDisplay.html');
|
||||
cy.wait('@getStatus')
|
||||
|
||||
cy.contains("Could NOT reach Skilltree Service");
|
||||
});
|
||||
@@ -229,8 +225,7 @@ context("Native JS Tests", () => {
|
||||
const v1Points = 'Earn up to 150 points';
|
||||
const v0Points = 'Earn up to 100 points';
|
||||
cy.createDefaultTinyProject();
|
||||
cy.server()
|
||||
.route(Cypress.env('tokenUrl'))
|
||||
cy.intercept(Cypress.env('tokenUrl'))
|
||||
.as("getToken");
|
||||
cy.backendAddSkill("skillv1", 1);
|
||||
cy.backendAddSkill("skillv2", 2);
|
||||
@@ -252,18 +247,16 @@ context("Native JS Tests", () => {
|
||||
|
||||
it('skillsClientVersion is reported correctly', () => {
|
||||
cy.createDefaultProject()
|
||||
|
||||
cy.server().route('POST', '/api/projects/proj1/skillsClientVersion').as('reportClientVersion')
|
||||
cy.intercept('POST', '/api/projects/proj1/skillsClientVersion', (req) => {
|
||||
expect(req.body).to.have.property('skillsClientVersion').and.to.contain('@skilltree/skills-client-js-')
|
||||
req.reply((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
expect(res.body).to.have.property('success').to.eq(true)
|
||||
})
|
||||
}).as('reportClientVersion')
|
||||
|
||||
cy.visit('/native/index.html')
|
||||
cy.wait('@reportClientVersion')
|
||||
cy.get('@reportClientVersion').then((xhr) => {
|
||||
expect(xhr.status).to.eq(200)
|
||||
expect(xhr.responseBody).to.have.property('success').to.eq(true)
|
||||
});
|
||||
cy.get('@reportClientVersion').should((xhr) => {
|
||||
expect(xhr.request.body, 'request body').to.have.property('skillsClientVersion').and.to.contain('@skilltree/skills-client-js-')
|
||||
});
|
||||
})
|
||||
|
||||
it('level component should be reactive', () => {
|
||||
@@ -294,4 +287,147 @@ context("Native JS Tests", () => {
|
||||
cy.contains('Level 1')
|
||||
})
|
||||
|
||||
if (Utils.skillsServiceVersionLaterThan('1.5.0')) {
|
||||
it('internal back button when when returning from an external page', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/native/clientDisplay.html?internalBackButton=true');
|
||||
// cy.wait('@getToken')
|
||||
|
||||
cy.clientDisplay(true).find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// navigate to Rank Overview that contains the back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('exist');
|
||||
|
||||
// now visit the "Report Skills" (external) page
|
||||
cy.get('[data-cy=reportSkillsLink]').click()
|
||||
cy.contains('Report Skills Examples');
|
||||
|
||||
// switch back to the the client display
|
||||
cy.get('[data-cy=userDisplayLink]').click()
|
||||
});
|
||||
|
||||
it('internal back button when when returning from an external page - multiple layers deep', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/native/clientDisplay.html?internalBackButton=true');
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview that contains the back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('exist');
|
||||
|
||||
// click the back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.cdBack('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.cdBack('User Skills');
|
||||
});
|
||||
|
||||
it('browser back button works correctly when internal back button is not present', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit("/native/clientDisplay.html?internalBackButton=false");
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
|
||||
// click the browser back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
});
|
||||
|
||||
it('deep link and reload', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// navigate to Rank Overview via direct link
|
||||
cy.visit('/native/clientDisplay.html?skillsClientDisplayPath=%2Frank#/showSkills');
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
// reload and confirm we are still on Rank Overview page
|
||||
cy.reload();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
});
|
||||
|
||||
it('back button after reload', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit("/native/clientDisplay.html?internalBackButton=false");
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
|
||||
cy.reload();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
// click the browser back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
});
|
||||
|
||||
it('route change is passed to the client app', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/native/clientDisplay.html?internalBackButton=true');
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/]');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/subjects/subj0]');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/subjects/subj0/rank]');
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -18,6 +18,10 @@ import Utils from "./Utils";
|
||||
const homePage = '/react/index.html#/'
|
||||
|
||||
context('React Tests', () => {
|
||||
|
||||
const laterThan_1_4_0 = Utils.skillsServiceVersionLaterThan('1.4.0');
|
||||
const noThemeBackground = laterThan_1_4_0 ? 'rgba(0, 0, 0, 0)' : 'rgb(255, 255, 255)';
|
||||
|
||||
it('level component should be reactive (skills reported directly to backend endpoint)', () => {
|
||||
cy.createDefaultProject()
|
||||
cy.visitHomePage(homePage);
|
||||
@@ -138,7 +142,7 @@ context('React Tests', () => {
|
||||
|
||||
it('skill display', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/react/index.html#/showSkills')
|
||||
cy.wait('@getToken')
|
||||
@@ -150,12 +154,12 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
.should('have.css', 'background-color').and('equal', noThemeBackground);
|
||||
})
|
||||
|
||||
it('skill display - summary only', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/react/index.html#/showSkills?isSummaryOnly=true')
|
||||
cy.wait('@getToken')
|
||||
@@ -167,12 +171,12 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
.should('have.css', 'background-color').and('equal', noThemeBackground);
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/react/index.html#/showSkills?themeName=Dark Blue')
|
||||
cy.wait('@getToken')
|
||||
@@ -189,7 +193,7 @@ context('React Tests', () => {
|
||||
|
||||
it('skill display - summary only - theme', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/react/index.html#/showSkills?themeName=Dark Blue&isSummaryOnly=true')
|
||||
cy.wait('@getToken')
|
||||
@@ -205,13 +209,11 @@ context('React Tests', () => {
|
||||
})
|
||||
|
||||
it('client display should display an error if skills service is down', () => {
|
||||
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route({
|
||||
method: 'GET',
|
||||
url: '/public/status',
|
||||
status: 503, // server is down
|
||||
response: {}
|
||||
cy.createDefaultTinyProject()
|
||||
cy.intercept('/public/status',
|
||||
{
|
||||
statusCode: 503, // server is down
|
||||
body: {}
|
||||
}).as('getStatus')
|
||||
cy.visit('/react/index.html#/showSkills')
|
||||
cy.wait('@getStatus')
|
||||
@@ -221,7 +223,7 @@ context('React Tests', () => {
|
||||
|
||||
it('only display skills up-to the provided version', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendAddSkill('skillv1', 1)
|
||||
cy.backendAddSkill('skillv2', 2)
|
||||
cy.visit('/react/index.html#/showSkills')
|
||||
@@ -243,17 +245,134 @@ context('React Tests', () => {
|
||||
|
||||
it('skillsClientVersion is reported correctly', () => {
|
||||
cy.createDefaultProject()
|
||||
cy.intercept('POST', '/api/projects/proj1/skillsClientVersion', (req) => {
|
||||
expect(req.body).to.have.property('skillsClientVersion').and.to.contain('@skilltree/skills-client-react-')
|
||||
req.reply((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
expect(res.body).to.have.property('success').to.eq(true)
|
||||
})
|
||||
}).as('reportClientVersion')
|
||||
|
||||
cy.visit('/react/index.html#/')
|
||||
|
||||
cy.server().route('POST', '/api/projects/proj1/skillsClientVersion').as('reportClientVersion')
|
||||
|
||||
cy.wait('@reportClientVersion')
|
||||
cy.get('@reportClientVersion').then((xhr) => {
|
||||
expect(xhr.status).to.eq(200)
|
||||
expect(xhr.responseBody).to.have.property('success').to.eq(true)
|
||||
});
|
||||
cy.get('@reportClientVersion').should((xhr) => {
|
||||
expect(xhr.request.body, 'request body').to.have.property('skillsClientVersion').and.to.contain('@skilltree/skills-client-react-')
|
||||
});
|
||||
})
|
||||
|
||||
if (Utils.skillsServiceVersionLaterThan('1.5.0')) {
|
||||
it('internal back button when when returning from an external page - multiple layers deep', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/react/index.html#/showSkills?internalBackButton=true');
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview that contains the back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('exist');
|
||||
|
||||
// click the back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.cdBack('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.cdBack('User Skills');
|
||||
});
|
||||
|
||||
it('browser back button works correctly when internal back button is not present', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/react/index.html#/showSkills?internalBackButton=false');
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
|
||||
// click the browser back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
});
|
||||
|
||||
it('deep link and reload', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// navigate to Rank Overview via direct link
|
||||
cy.visit('/react/index.html?skillsClientDisplayPath=%2Frank#/showSkills');
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
// reload and confirm we are still on Rank Overview page
|
||||
cy.reload();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
});
|
||||
|
||||
it('back button after reload', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/react/index.html#/showSkills?internalBackButton=false');
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
|
||||
cy.reload();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
// click the browser back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
});
|
||||
|
||||
it('route change is passed to the client app', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/react/index.html#/showSkills?internalBackButton=false');
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/]');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/subjects/subj0]');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/subjects/subj0/rank]');
|
||||
});
|
||||
}
|
||||
})
|
||||
@@ -19,6 +19,12 @@ const homePage = '/vuejs#/'
|
||||
|
||||
context('Vue Tests', () => {
|
||||
|
||||
const laterThan_1_4_0 = Utils.skillsServiceVersionLaterThan('1.4.0');
|
||||
const laterThan_1_5_0 = Utils.skillsServiceVersionLaterThan('1.5.0');
|
||||
const missingSkillErrorCode = laterThan_1_4_0 ? 404 : 400;
|
||||
const noThemeBackground = laterThan_1_4_0 ? 'rgba(0, 0, 0, 0)' : 'rgb(255, 255, 255)';
|
||||
const clientDisplayWithInternalBackButtonParams = laterThan_1_5_0 ? '?refreshPage=false&internalBackButton=true' : '?refreshPage=false';
|
||||
|
||||
it('level component should be reactive', () => {
|
||||
// cy.window().then(win => {
|
||||
// const skillsLogger = win.skillsLogger;
|
||||
@@ -117,6 +123,7 @@ context('Vue Tests', () => {
|
||||
cy.get('[data-cy=globalEventResult]').contains('"skillApplied": true')
|
||||
cy.get('[data-cy=globalEventResult]').contains(/completed": [[][^]*"type": "Overall",[^]\s*"level": 1/)
|
||||
})
|
||||
|
||||
it('global event does not update when skill reported for a different project', () => {
|
||||
cy.createDefaultProject()
|
||||
cy.createDefaultTinyProject('proj2')
|
||||
@@ -129,6 +136,7 @@ context('Vue Tests', () => {
|
||||
cy.contains('Level 0')
|
||||
cy.get('[data-cy=globalEventResult]').should('be.empty');
|
||||
})
|
||||
|
||||
it('global event is not reported when skill is not applied', () => {
|
||||
cy.createDefaultProject()
|
||||
cy.reportSkillForUser('IronMan', Cypress.env('proxyUser'))
|
||||
@@ -142,6 +150,7 @@ context('Vue Tests', () => {
|
||||
|
||||
cy.get('[data-cy=globalEventResult]').should('be.empty');
|
||||
})
|
||||
|
||||
it('level component should not update when admin reports skill for other user', () => {
|
||||
|
||||
cy.createDefaultProject()
|
||||
@@ -159,16 +168,15 @@ context('Vue Tests', () => {
|
||||
it('v-skill directive on click', () => {
|
||||
cy.createDefaultProject(1, 2, 50, 2)
|
||||
|
||||
cy.server().route('POST', '/api/projects/proj1/skills/IronMan').as('postSkill')
|
||||
cy.intercept('POST', '/api/projects/proj1/skills/IronMan').as('postSkill')
|
||||
|
||||
cy.visit('/vuejs#/')
|
||||
|
||||
Cypress.Commands.add("clickOnDirectiveBtn", (skillApplied = true) => {
|
||||
cy.get('#SkillsDirectiveClickEvent button').click()
|
||||
cy.wait('@postSkill')
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
expect(xhr.status).to.eq(200)
|
||||
expect(xhr.responseBody).to.have.property('skillApplied').to.eq(skillApplied)
|
||||
cy.wait('@postSkill').then((intercept) => {
|
||||
expect(intercept.response.statusCode).to.eq(200)
|
||||
expect(intercept.response.body).to.have.property('skillApplied').to.eq(skillApplied)
|
||||
});
|
||||
})
|
||||
|
||||
@@ -177,19 +185,17 @@ context('Vue Tests', () => {
|
||||
cy.clickOnDirectiveBtn(false)
|
||||
})
|
||||
|
||||
|
||||
it('v-skill directive on input', () => {
|
||||
cy.createDefaultProject(1, 2, 50, 2)
|
||||
cy.server().route('POST', '/api/projects/proj1/skills/Thor').as('postSkill')
|
||||
cy.intercept('POST', '/api/projects/proj1/skills/Thor').as('postSkill')
|
||||
|
||||
cy.visitHomePage(homePage);
|
||||
|
||||
Cypress.Commands.add("typeToInput", (skillApplied = true) => {
|
||||
cy.get('#SkillsDirectiveInputEvent input').type('h')
|
||||
cy.wait('@postSkill')
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
expect(xhr.status).to.eq(200)
|
||||
expect(xhr.responseBody).to.have.property('skillApplied').to.eq(skillApplied)
|
||||
cy.wait('@postSkill').then((intercept) => {
|
||||
expect(intercept.response.statusCode).to.eq(200)
|
||||
expect(intercept.response.body).to.have.property('skillApplied').to.eq(skillApplied)
|
||||
});
|
||||
})
|
||||
|
||||
@@ -200,47 +206,42 @@ context('Vue Tests', () => {
|
||||
|
||||
it('v-skill directive on click with error', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route('POST', '/api/projects/proj1/skills/DoesNotExist').as('postSkill')
|
||||
cy.intercept('POST', '/api/projects/proj1/skills/DoesNotExist').as('postSkill')
|
||||
|
||||
cy.visitHomePage(homePage);
|
||||
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
expect(xhr.status).to.eq(400)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
cy.wait('@postSkill').then((intercept) => {
|
||||
expect(intercept.response.statusCode).to.eq(missingSkillErrorCode)
|
||||
expect(intercept.response.body).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
|
||||
it('v-skill directive on input with error', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route('POST', '/api/projects/proj1/skills/DoesNotExist').as('postSkill')
|
||||
cy.intercept('POST', '/api/projects/proj1/skills/DoesNotExist').as('postSkill')
|
||||
|
||||
cy.visitHomePage(homePage);
|
||||
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
expect(xhr.status).to.eq(400)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
cy.wait('@postSkill').then((intercept) => {
|
||||
expect(intercept.response.statusCode).to.eq(missingSkillErrorCode)
|
||||
expect(intercept.response.body).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
|
||||
it('skill display', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/vuejs#/showSkills')
|
||||
cy.wait('@getToken')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('My Level')
|
||||
cy.wrapIframe().contains('50 Points earned Today')
|
||||
cy.wrapIframe().contains('Subject 0')
|
||||
cy.clientDisplay(true).contains('My Level')
|
||||
cy.clientDisplay().contains('50 Points earned Today')
|
||||
cy.clientDisplay().contains('Subject 0')
|
||||
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
cy.clientDisplay().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', noThemeBackground);
|
||||
})
|
||||
|
||||
it('Proxy Skills Display', () => {
|
||||
@@ -248,86 +249,81 @@ context('Vue Tests', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.createDefaultTinyProject('proj2')
|
||||
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.server().route('/api/users/proj2/user2/token').as('getToken2')
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.intercept('/api/users/proj2/user2/token').as('getToken2')
|
||||
cy.intercept('api/projects/proj1/rank').as('getRankUser2')
|
||||
cy.intercept('api/projects/proj1/pointHistory').as('getPointsHistoryUser2')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/vuejs#/showSkills')
|
||||
cy.wait('@getToken')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('My Level')
|
||||
cy.wrapIframe().contains('50 Points earned Today')
|
||||
cy.wrapIframe().contains('Subject 0')
|
||||
|
||||
// cy.wait('@getToken')
|
||||
cy.clientDisplay(true).contains('My Level')
|
||||
cy.clientDisplay().contains('50 Points earned Today')
|
||||
cy.clientDisplay().contains('Subject 0')
|
||||
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
cy.clientDisplay().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', noThemeBackground);
|
||||
|
||||
cy.visit('/vuejs#/proxyShowSkills')
|
||||
cy.wait('@getToken2')
|
||||
cy.wrapIframe().contains('My Level')
|
||||
cy.wrapIframe().contains('0 Points earned Today')
|
||||
cy.wait('@getRankUser2')
|
||||
cy.wait('@getPointsHistoryUser2')
|
||||
cy.clientDisplay().contains('My Level')
|
||||
cy.clientDisplay().contains('0 Points earned Today')
|
||||
}
|
||||
})
|
||||
|
||||
it('skill display - summary only', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/vuejs#/showSkills?isSummaryOnly=true')
|
||||
cy.wait('@getToken')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('My Level')
|
||||
cy.wrapIframe().contains('50 Points earned Today')
|
||||
cy.wrapIframe().contains('Subject 0').should('not.exist')
|
||||
cy.clientDisplay(true).contains('My Level')
|
||||
cy.clientDisplay().contains('50 Points earned Today')
|
||||
cy.clientDisplay().contains('Subject 0').should('not.exist')
|
||||
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
cy.clientDisplay().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', noThemeBackground);
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/vuejs#/showSkills?themeName=Dark Blue')
|
||||
cy.wait('@getToken')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('My Level')
|
||||
cy.wrapIframe().contains('50 Points earned Today')
|
||||
cy.wrapIframe().contains('Subject 0')
|
||||
cy.clientDisplay(true).contains('My Level')
|
||||
cy.clientDisplay().contains('50 Points earned Today')
|
||||
cy.clientDisplay().contains('Subject 0')
|
||||
|
||||
// verify dark blue background of hex #152E4d
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
cy.clientDisplay().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(21, 46, 77)');
|
||||
})
|
||||
|
||||
it('skill display - summary only - theme', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.visit('/vuejs#/showSkills?themeName=Dark Blue&isSummaryOnly=true')
|
||||
cy.wait('@getToken')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('My Level')
|
||||
cy.wrapIframe().contains('50 Points earned Today')
|
||||
cy.wrapIframe().contains('Subject 0').should('not.exist')
|
||||
cy.clientDisplay(true).contains('My Level')
|
||||
cy.clientDisplay().contains('50 Points earned Today')
|
||||
cy.clientDisplay().contains('Subject 0').should('not.exist')
|
||||
|
||||
// verify dark blue background of hex #152E4d
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
cy.clientDisplay().find('.skills-page-title-text-color')
|
||||
.should('have.css', 'background-color').and('equal', 'rgb(21, 46, 77)');
|
||||
})
|
||||
|
||||
it('client display should display an error if skills service is down', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route({
|
||||
method: 'GET',
|
||||
url: '/public/status',
|
||||
status: 503, // server is down
|
||||
response: {}
|
||||
cy.createDefaultTinyProject()
|
||||
cy.intercept('/public/status',
|
||||
{
|
||||
statusCode: 503, // server is down
|
||||
body: {}
|
||||
}).as('getStatus')
|
||||
cy.visit('/vuejs#/showSkills')
|
||||
cy.wait('@getStatus')
|
||||
@@ -337,39 +333,37 @@ context('Vue Tests', () => {
|
||||
|
||||
it('only display skills up-to the provided version', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendAddSkill('skillv1', 1)
|
||||
cy.backendAddSkill('skillv2', 2)
|
||||
|
||||
cy.visit('/vuejs#/showSkills')
|
||||
cy.wait('@getToken')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('Earn up to 200 points')
|
||||
cy.clientDisplay(true).contains('Earn up to 200 points')
|
||||
|
||||
cy.visit('/vuejs#/')
|
||||
cy.get('[data-cy=reportSkillsLink]').should('be.visible');
|
||||
|
||||
cy.visit('/vuejs#/showSkills?skillsVersion=1')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('Earn up to 150 points')
|
||||
cy.clientDisplay().contains('Earn up to 150 points')
|
||||
|
||||
cy.visit('/vuejs#/')
|
||||
cy.get('[data-cy=reportSkillsLink]').should('be.visible');
|
||||
|
||||
cy.visit('/vuejs#/showSkills?skillsVersion=0')
|
||||
cy.wait('@getToken')
|
||||
cy.wrapIframe().contains('Earn up to 100 points')
|
||||
cy.clientDisplay().contains('Earn up to 100 points')
|
||||
});
|
||||
|
||||
it('skillsClientVersion is reported correctly', () => {
|
||||
cy.createDefaultProject()
|
||||
cy.intercept('POST', '/api/projects/proj1/skillsClientVersion', (req) => {
|
||||
expect(req.body).to.have.property('skillsClientVersion').and.to.contain('@skilltree/skills-client-vue-')
|
||||
req.reply((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
expect(res.body).to.have.property('success').to.eq(true)
|
||||
})
|
||||
}).as('reportClientVersion')
|
||||
|
||||
cy.visit('/vuejs#/')
|
||||
|
||||
cy.server().route('POST', '/api/projects/proj1/skillsClientVersion').as('reportClientVersion')
|
||||
|
||||
cy.wait('@reportClientVersion')
|
||||
cy.get('@reportClientVersion').then((xhr) => {
|
||||
expect(xhr.status).to.eq(200)
|
||||
expect(xhr.responseBody).to.have.property('success').to.eq(true)
|
||||
});
|
||||
cy.get('@reportClientVersion').should((xhr) => {
|
||||
expect(xhr.request.body, 'request body').to.have.property('skillsClientVersion').and.to.contain('@skilltree/skills-client-vue-')
|
||||
});
|
||||
})
|
||||
|
||||
/*it('Proxy User Display', () => {
|
||||
@@ -392,7 +386,7 @@ context('Vue Tests', () => {
|
||||
cy.clickSubmit()
|
||||
cy.contains('Level 1')
|
||||
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
cy.get('[data-cy=userDisplayLink]').click();
|
||||
//cy.contains('User Display').click();
|
||||
@@ -414,20 +408,20 @@ context('Vue Tests', () => {
|
||||
if (Utils.skillsServiceVersionLaterThan('1.2.0')) {
|
||||
it('back button when when returning from an external page', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.intercept(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/vuejs#/showSkills?refreshPage=false')
|
||||
cy.wait('@getToken')
|
||||
cy.visit('/vuejs#/showSkills'+clientDisplayWithInternalBackButtonParams)
|
||||
// cy.wait('@getToken')
|
||||
|
||||
cy.wrapIframe().find('[data-cy=back]').should('not.exist');
|
||||
cy.wrapIframe().contains('User Skills');
|
||||
cy.clientDisplay(true).find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// navigate to Rank Overview that contains the back button
|
||||
cy.wrapIframe().find('[data-cy=myRank]').click();
|
||||
cy.wrapIframe().contains('Rank Overview');
|
||||
cy.wrapIframe().find('[data-cy=back]').should('exist');
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('exist');
|
||||
|
||||
// now visit the "Report Skills" (external) page
|
||||
cy.get('[data-cy=reportSkillsLink]').click()
|
||||
@@ -441,23 +435,21 @@ context('Vue Tests', () => {
|
||||
if (Utils.skillsServiceVersionLaterThan('1.2.0')) {
|
||||
it('back button when when returning from an external page - multiple layers deep', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.server().route(Cypress.env('tokenUrl')).as('getToken')
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/vuejs#/showSkills?refreshPage=false')
|
||||
cy.wait('@getToken')
|
||||
cy.visit('/vuejs#/showSkills'+clientDisplayWithInternalBackButtonParams)
|
||||
|
||||
cy.wrapIframe().find('[data-cy=back]').should('not.exist');
|
||||
cy.wrapIframe().contains('User Skills');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview that contains the back button
|
||||
cy.wrapIframe().find('[data-cy=myRank]').click();
|
||||
cy.wrapIframe().contains('Rank Overview');
|
||||
cy.wrapIframe().find('[data-cy=back]').should('exist');
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('exist');
|
||||
|
||||
// now visit the "Report Skills" (external) page
|
||||
cy.get('[data-cy=reportSkillsLink]').click()
|
||||
@@ -466,7 +458,7 @@ context('Vue Tests', () => {
|
||||
// switch back to the the client display
|
||||
cy.get('[data-cy=userDisplayLink]').click()
|
||||
// verify we are still on the Rank Overview page
|
||||
cy.wrapIframe().contains('Rank Overview');
|
||||
cy.clientDisplay(true).contains('Rank Overview');
|
||||
|
||||
// click the back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
@@ -477,5 +469,97 @@ context('Vue Tests', () => {
|
||||
});
|
||||
}
|
||||
|
||||
if (Utils.skillsServiceVersionLaterThan('1.5.0')) {
|
||||
it('browser back button works correctly when internal back button is not present', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/vuejs#/showSkills?internalBackButton=false');
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
|
||||
// click the browser back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
});
|
||||
|
||||
it('deep link and reload', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// navigate to Rank Overview via direct link
|
||||
cy.visit('/vuejs/?skillsClientDisplayPath=%2Frank#/showSkills?refreshPage=true');
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
// reload and confirm we are still on Rank Overview page
|
||||
cy.reload();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
});
|
||||
|
||||
it('back button after reload', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/vuejs#/showSkills?internalBackButton=false');
|
||||
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
cy.clientDisplay().find('[data-cy=back]').should('not.exist');
|
||||
|
||||
cy.reload();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
// click the browser back button and verify that we are still in the
|
||||
// client display (Subject page)
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('Subject 0');
|
||||
|
||||
// then back one more time and we should be back on the client display home page
|
||||
cy.go('back') // browser back button
|
||||
cy.clientDisplay().contains('User Skills');
|
||||
});
|
||||
|
||||
it('route change is passed to the client app', () => {
|
||||
cy.createDefaultTinyProject()
|
||||
cy.backendPost('/api/projects/proj1/skills/Thor', {userId: Cypress.env('proxyUser'), timestamp: Date.now()})
|
||||
|
||||
// visit client display
|
||||
cy.visit('/vuejs#/showSkills?internalBackButton=false');
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/]');
|
||||
|
||||
// to subject page
|
||||
cy.cdClickSubj(0, 'Subject 0');
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/subjects/subj0]');
|
||||
|
||||
// navigate to Rank Overview and that it does NOT contains the internal back button
|
||||
cy.clientDisplay().find('[data-cy=myRank]').click();
|
||||
cy.clientDisplay().contains('Rank Overview');
|
||||
|
||||
cy.get('[data-cy=skillsDisplayPath]').contains('Skills Display Path: [/subjects/subj0/rank]');
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
@@ -182,7 +182,7 @@ Cypress.Commands.add("cdClickSubj", (subjIndex, expectedTitle) => {
|
||||
|
||||
Cypress.Commands.add("cdBack", (expectedTitle = 'User Skills') => {
|
||||
cy.wrapIframe().find('[data-cy=back]').click()
|
||||
cy.wrapIframe().find('[data-cy=title]').contains(expectedTitle);
|
||||
cy.wrapIframe().contains(expectedTitle);
|
||||
|
||||
// back button should not exist on the home page, whose title is the default value
|
||||
if (expectedTitle === 'User Skills') {
|
||||
@@ -190,6 +190,16 @@ Cypress.Commands.add("cdBack", (expectedTitle = 'User Skills') => {
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add("clientDisplay", (firstVisit=false, project='proj1') => {
|
||||
cy.intercept(`/api/projects/${project}/rank`).as(`getRank${project}`)
|
||||
cy.intercept(`/api/projects/${project}/pointHistory`).as(`getPointsHistory${project}`)
|
||||
if (firstVisit) {
|
||||
cy.wait(`@getRank${project}`)
|
||||
cy.wait(`@getPointsHistory${project}`)
|
||||
}
|
||||
return cy.wrapIframe();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('wrapIframe', () => {
|
||||
return cy.get('iframe')
|
||||
.its('0.contentDocument.body').should('not.be.empty')
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"dev:removeNpmLinks": "mvn --batch-mode clean package && java -cp target/skills-int-e2e-test-*.jar -Dloader.main=skills.RemoveNpmLinks org.springframework.boot.loader.PropertiesLauncher"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cypress": "6.2.0",
|
||||
"cypress": "6.6.0",
|
||||
"license-check-and-add": "3.0.4",
|
||||
"license-checker": "25.0.1",
|
||||
"semver": "7.3.2",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<version>3.1.1-SNAPSHOT</version>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skills-int-e2e-test</artifactId>
|
||||
<description>End to End tests for Skills client libs using skills-int-service app</description>
|
||||
|
||||
+2
@@ -16,4 +16,6 @@ skills.service.password=password
|
||||
skills.service.serviceUrl=http://localhost:8080
|
||||
skills.service.projectId=proj1
|
||||
skills.service.authenticator=http://localhost:8090/api/users/user1/token
|
||||
skills.service.proxiedProjectId=proj2
|
||||
skills.service.proxiedUserId=user2
|
||||
logging.pattern.console=EXAMPLES-APP %clr(%d{yy-MM-dd E HH:mm:ss.SSS}){blue} %clr(%-5p) %clr(${PID}){faint} %clr(---){faint} %clr([%8.15t]){cyan} %clr(%-40.40logger{0}){blue} %clr(:){red} %clr(%m){faint}%n
|
||||
+1
-1
@@ -50,7 +50,7 @@ class NpmProjBuilder {
|
||||
new NpmProj(name: "skills-int-client-js", doOthersLinkToMe: false, initialVersion: '2.0.0'),
|
||||
new NpmProj(name: "skills-int-client-vue", doOthersLinkToMe: false, initialVersion: '2.0.0'),
|
||||
new NpmProj(name: "skills-int-client-react", doOthersLinkToMe: false, reactApp: true, initialVersion: '2.0.0'),
|
||||
new NpmProj(name: "skills-int-client-ng", doOthersLinkToMe: false, initialVersion: '3.0.0'),
|
||||
new NpmProj(name: "skills-int-client-ng", doOthersLinkToMe: false, angularApp: true, initialVersion: '3.0.0'),
|
||||
]
|
||||
|
||||
private void assertExist() {
|
||||
|
||||
+6
-3
@@ -63,7 +63,7 @@ class SetupNpmLinks {
|
||||
projs.each { NpmProj npmProj ->
|
||||
if (!npmProj.isAngularModule()) {
|
||||
// angular modules were installed within createLinks()
|
||||
npmProj.exec("npm install")
|
||||
npmProj.exec("npm install --force")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,10 @@ class SetupNpmLinks {
|
||||
titlePrinter.printTitle("link")
|
||||
projs.findAll({ it.hasLinksToOtherProjects }).each { NpmProj npmProj ->
|
||||
npmProj.skillsDependenciesFromPackageJson.each {
|
||||
titlePrinter.printSubTitle("Linking module [${it}]")
|
||||
titlePrinter.printSubTitle("Linking module [${it}] in project [${npmProj}]")
|
||||
if (npmProj.getAngularApp() || npmProj.getAngularModule()) {
|
||||
npmProj.exec("npm install --force")
|
||||
}
|
||||
npmProj.exec("npm link ${it}".toString())
|
||||
if (npmProj.getAngularModule()) {
|
||||
File origLoc = npmProj.loc
|
||||
@@ -133,7 +136,7 @@ class SetupNpmLinks {
|
||||
File origLoc
|
||||
if (it.isAngularModule()) {
|
||||
titlePrinter.printTitle("install and build angular module")
|
||||
it.exec("npm install")
|
||||
it.exec("npm install --force")
|
||||
it.exec("npm run build")
|
||||
origLoc = it.loc;
|
||||
it.loc = it.getAngularModuleLinkDir(true)
|
||||
|
||||
+2
-1
@@ -85,7 +85,8 @@ class TestDashboardBackwardCompat {
|
||||
Resource found = resources.find { it.filename.endsWith(patchFile) }
|
||||
if (found) {
|
||||
FileUtils.copyToFile(found.inputStream, new File(workDir, patchFile))
|
||||
new ProcessRunner(loc: workDir).run("git apply ${patchFile}")
|
||||
String result = new ProcessRunner(loc: workDir).run("git apply --verbose ${patchFile}").sout
|
||||
log.info(result)
|
||||
} else{
|
||||
log.info("Patch file [${patchFile} not found, contining with applying any patches.")
|
||||
}
|
||||
|
||||
+134
-32
@@ -1,3 +1,16 @@
|
||||
diff --git a/skills-client-integration/pom.xml b/skills-client-integration/pom.xml
|
||||
index 745a168..90d231c 100755
|
||||
--- a/skills-client-integration/pom.xml
|
||||
+++ b/skills-client-integration/pom.xml
|
||||
@@ -33,7 +33,7 @@
|
||||
<properties>
|
||||
<!--suppress UnresolvedMavenProperty -->
|
||||
<nexusServer>${nexus.url}</nexusServer>
|
||||
- <node.version>v11.6.0</node.version>
|
||||
+ <node.version>v14.15.0</node.version>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress.json b/skills-client-integration/skills-int-e2e-test/cypress.json
|
||||
index 52f9451..a87626c 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress.json
|
||||
@@ -14,11 +27,95 @@ index 52f9451..a87626c 100644
|
||||
+ "openMode": 0
|
||||
+ }
|
||||
}
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
index 2b73362..2787c53 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
@@ -148,7 +148,7 @@ context("Native JS Tests", () => {
|
||||
cy.wrap(body)
|
||||
.find(".skills-page-title-text-color")
|
||||
.should("have.css", "background-color")
|
||||
- .and("equal", "rgb(255, 255, 255)");
|
||||
+ .and("equal", "rgba(0, 0, 0, 0)");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -175,7 +175,7 @@ context("Native JS Tests", () => {
|
||||
cy.wrap(body)
|
||||
.find(".skills-page-title-text-color")
|
||||
.should("have.css", "background-color")
|
||||
- .and("equal", "rgb(255, 255, 255)");
|
||||
+ .and("equal", "rgba(0, 0, 0, 0)");
|
||||
});
|
||||
});
|
||||
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
index 1cc8b29..8e4895f 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
@@ -167,7 +167,7 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
})
|
||||
|
||||
@@ -186,7 +186,7 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
})
|
||||
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
index 2283896..665e697 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
@@ -219,7 +219,7 @@ context('Vue Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -233,7 +233,7 @@ context('Vue Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -255,7 +255,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
})
|
||||
|
||||
@@ -274,7 +274,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
})
|
||||
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/package.json b/skills-client-integration/skills-int-e2e-test/package.json
|
||||
index 2dfe4e3..04a2791 100644
|
||||
index 2dfe4e3..6d7ec41 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/package.json
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/package.json
|
||||
@@ -18,12 +18,17 @@
|
||||
@@ -18,16 +18,21 @@
|
||||
"cy:open:dev:react": "cypress open --config baseUrl=http://localhost:8083",
|
||||
"integration:start": "java -Dspring.config.location=classpath:/application.properties,file:serverConfigs/integration_application.properties -jar ../skills-int-service/target/skills-int-service-*.jar",
|
||||
"integration:start:release": "java -Dspring.config.location=classpath:/application.properties,file:serverConfigs/integration_application.properties -jar ./target/servicesJars/skills-int-service-*.jar",
|
||||
@@ -38,6 +135,11 @@ index 2dfe4e3..04a2791 100644
|
||||
"release": "release-it --dry-run"
|
||||
},
|
||||
"devDependencies": {
|
||||
- "cypress": "4.1.0",
|
||||
+ "cypress": "6.2.0",
|
||||
"license-check-and-add": "3.0.4",
|
||||
"license-checker": "25.0.1",
|
||||
"semver": "7.1.2",
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/pom.xml b/skills-client-integration/skills-int-e2e-test/pom.xml
|
||||
index 10d22b8..f28ba3e 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/pom.xml
|
||||
@@ -80,16 +182,16 @@ index 80ed5f3..ad2889c 100644
|
||||
@@ -15,7 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
package skills
|
||||
|
||||
|
||||
-import callStack.profiler.Profile
|
||||
+//import callStack.profiler.Profile
|
||||
import groovy.util.logging.Slf4j
|
||||
import org.apache.commons.io.FileUtils
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class DownloadServiceJars {
|
||||
// internal
|
||||
TitlePrinter titlePrinter = new TitlePrinter()
|
||||
|
||||
|
||||
- @Profile
|
||||
+ // @Profile
|
||||
void cleanOutputDir(){
|
||||
@@ -98,7 +200,7 @@ index 80ed5f3..ad2889c 100644
|
||||
@@ -40,7 +40,7 @@ class DownloadServiceJars {
|
||||
// outputDir.mkdirs()
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ //@Profile
|
||||
void remove(String artifact, String version) {
|
||||
@@ -107,7 +209,7 @@ index 80ed5f3..ad2889c 100644
|
||||
@@ -49,7 +49,7 @@ class DownloadServiceJars {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ //@Profile
|
||||
void download(String artifact, String version) {
|
||||
@@ -120,16 +222,16 @@ index 168e90d..ea13f9c 100644
|
||||
@@ -15,7 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
package skills
|
||||
|
||||
|
||||
-import callStack.profiler.Profile
|
||||
+//import callStack.profiler.Profile
|
||||
import groovy.util.logging.Slf4j
|
||||
|
||||
|
||||
@Slf4j
|
||||
@@ -57,7 +57,7 @@ class NpmProjBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ // @Profile
|
||||
List<NpmProj> build() {
|
||||
@@ -142,16 +244,16 @@ index 4b8ba60..724ca5b 100644
|
||||
@@ -15,7 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
package skills
|
||||
|
||||
|
||||
-import callStack.profiler.Profile
|
||||
+//import callStack.profiler.Profile
|
||||
import groovy.util.logging.Slf4j
|
||||
import org.apache.commons.io.FileUtils
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class ProjectsOps {
|
||||
new File(workDir, "skills-client")
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ // @Profile
|
||||
private void clearWorkDir() {
|
||||
@@ -160,7 +262,7 @@ index 4b8ba60..724ca5b 100644
|
||||
@@ -51,7 +51,7 @@ class ProjectsOps {
|
||||
workDir.mkdirs()
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ // @Profile
|
||||
void checkoutLinkedNpmLibs(String switchToBranch = null) {
|
||||
@@ -168,8 +270,8 @@ index 4b8ba60..724ca5b 100644
|
||||
titlePrinter.printTitle("Checkout skills-client")
|
||||
@@ -68,7 +68,7 @@ class ProjectsOps {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
- @Profile
|
||||
+ //@Profile
|
||||
void buildClientIntApp() {
|
||||
@@ -177,8 +279,8 @@ index 4b8ba60..724ca5b 100644
|
||||
File loc = new File(skillsClient, "skills-client-integration")
|
||||
@@ -76,7 +76,7 @@ class ProjectsOps {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
- @Profile
|
||||
+ //@Profile
|
||||
void runCypressTests(File location, String msg, List<String> cypressEnv = [], String npmIntegrationNamespace = "integration") {
|
||||
@@ -191,14 +293,14 @@ index 0193982..cfad14d 100644
|
||||
@@ -15,8 +15,8 @@ limitations under the License.
|
||||
*/
|
||||
package skills
|
||||
|
||||
|
||||
-import callStack.profiler.CProf
|
||||
-import callStack.profiler.Profile
|
||||
+//import callStack.profiler.CProf
|
||||
+//import callStack.profiler.Profile
|
||||
import groovy.util.logging.Slf4j
|
||||
import org.apache.commons.io.FileUtils
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class SetupNpmLinks {
|
||||
static void main(String[] args) {
|
||||
boolean shouldPrune = args.find({ it.equalsIgnoreCase("--prune") })
|
||||
@@ -206,12 +308,12 @@ index 0193982..cfad14d 100644
|
||||
- log.info("Execution Prof:\n{}", CProf.prettyPrint())
|
||||
+ //log.info("Execution Prof:\n{}", CProf.prettyPrint())
|
||||
}
|
||||
|
||||
|
||||
// configure
|
||||
@@ -44,7 +44,7 @@ class SetupNpmLinks {
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ // @Profile
|
||||
void doLink() {
|
||||
@@ -220,7 +322,7 @@ index 0193982..cfad14d 100644
|
||||
@@ -57,7 +57,7 @@ class SetupNpmLinks {
|
||||
build()
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ //@Profile
|
||||
void removeAnyExistingLinks() {
|
||||
@@ -229,7 +331,7 @@ index 0193982..cfad14d 100644
|
||||
@@ -78,7 +78,7 @@ class SetupNpmLinks {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ //@Profile
|
||||
private void build() {
|
||||
@@ -238,7 +340,7 @@ index 0193982..cfad14d 100644
|
||||
@@ -86,7 +86,7 @@ class SetupNpmLinks {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ //@Profile
|
||||
private void validateLinks() {
|
||||
@@ -247,7 +349,7 @@ index 0193982..cfad14d 100644
|
||||
@@ -106,7 +106,7 @@ class SetupNpmLinks {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ // @Profile
|
||||
private void npmLinkToSkills() {
|
||||
@@ -256,7 +358,7 @@ index 0193982..cfad14d 100644
|
||||
@@ -117,7 +117,7 @@ class SetupNpmLinks {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ //@Profile
|
||||
private void npmLinkToReact() {
|
||||
@@ -265,7 +367,7 @@ index 0193982..cfad14d 100644
|
||||
@@ -127,7 +127,7 @@ class SetupNpmLinks {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ //@Profile
|
||||
private void createLinks() {
|
||||
@@ -274,7 +376,7 @@ index 0193982..cfad14d 100644
|
||||
@@ -138,7 +138,7 @@ class SetupNpmLinks {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ //@Profile
|
||||
private void npmInstall() {
|
||||
@@ -287,7 +389,7 @@ index 55c9c7c..d399b1b 100644
|
||||
@@ -15,8 +15,8 @@ limitations under the License.
|
||||
*/
|
||||
package skills
|
||||
|
||||
|
||||
-import callStack.profiler.CProf
|
||||
-import callStack.profiler.Profile
|
||||
+//import callStack.profiler.CProf
|
||||
@@ -298,9 +400,9 @@ index 55c9c7c..d399b1b 100644
|
||||
@@ -64,7 +64,7 @@ class TestDashboardBackwardCompat {
|
||||
log.info("Profile \n{}", CProf.prettyPrint())
|
||||
}
|
||||
|
||||
|
||||
- @Profile
|
||||
+ // @Profile
|
||||
private void doTest() {
|
||||
|
||||
|
||||
titlePrinter.printTitle("Release Dashboard")
|
||||
+179
@@ -1,3 +1,23 @@
|
||||
diff --git a/skills-client-integration/skills-int-client-ng/package.json b/skills-client-integration/skills-int-client-ng/package.json
|
||||
index ed5628a..d21af9c 100644
|
||||
--- a/skills-client-integration/skills-int-client-ng/package.json
|
||||
+++ b/skills-client-integration/skills-int-client-ng/package.json
|
||||
@@ -34,7 +34,7 @@
|
||||
"bootstrap": "4.5.0",
|
||||
"jquery": "3.5.1",
|
||||
"js-beautify": "1.10.2",
|
||||
- "ngx-highlightjs": "4.1.0-beta",
|
||||
+ "ngx-highlightjs": "4.1.3",
|
||||
"rxjs": "6.5.5",
|
||||
"tslib": "2.0.0",
|
||||
"zone.js": "0.10.3"
|
||||
@@ -61,4 +61,4 @@
|
||||
"tslint": "6.1.0",
|
||||
"typescript": "3.9.5"
|
||||
}
|
||||
-}
|
||||
\ No newline at end of file
|
||||
+}
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress.json b/skills-client-integration/skills-int-e2e-test/cypress.json
|
||||
index 52f9451..a87626c 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress.json
|
||||
@@ -14,3 +34,162 @@ index 52f9451..a87626c 100644
|
||||
+ "openMode": 0
|
||||
+ }
|
||||
}
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
index cbe8938..5aea457 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
@@ -208,7 +208,7 @@ context('Angular Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -222,7 +222,7 @@ context('Angular Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -244,7 +244,7 @@ context('Angular Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
})
|
||||
|
||||
@@ -263,7 +263,7 @@ context('Angular Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
})
|
||||
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
index af68cba..95aa71e 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
@@ -118,7 +118,7 @@ context("Native JS Tests", () => {
|
||||
cy.wrap(body)
|
||||
.find(".skills-page-title-text-color")
|
||||
.should("have.css", "background-color")
|
||||
- .and("equal", "rgb(255, 255, 255)");
|
||||
+ .and("equal", "rgba(0, 0, 0, 0)");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -142,7 +142,7 @@ context("Native JS Tests", () => {
|
||||
cy.wrap(body)
|
||||
.find(".skills-page-title-text-color")
|
||||
.should("have.css", "background-color")
|
||||
- .and("equal", "rgb(255, 255, 255)");
|
||||
+ .and("equal", "rgba(0, 0, 0, 0)");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -169,7 +169,7 @@ context("Native JS Tests", () => {
|
||||
cy.wrap(body)
|
||||
.find(".skills-page-title-text-color")
|
||||
.should("have.css", "background-color")
|
||||
- .and("equal", "rgb(255, 255, 255)");
|
||||
+ .and("equal", "rgba(0, 0, 0, 0)");
|
||||
});
|
||||
});
|
||||
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
index d0d7a1d..3ca2982 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
@@ -153,7 +153,7 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
})
|
||||
|
||||
@@ -172,7 +172,7 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
})
|
||||
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
index b010108..95e7b93 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
@@ -204,7 +204,7 @@ context('Vue Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -218,7 +218,7 @@ context('Vue Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -240,7 +240,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
})
|
||||
|
||||
@@ -259,7 +259,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
})
|
||||
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js b/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
index 6a65d80..689aa4f 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
@@ -171,7 +171,7 @@ Cypress.Commands.add("cdClickSubj", (body, subjIndex, expectedTitle) => {
|
||||
|
||||
Cypress.Commands.add("cdBack", (body, expectedTitle = 'User Skills') => {
|
||||
cy.wrap(body).find('[data-cy=back]').click()
|
||||
- cy.wrap(body).find('h2').contains(expectedTitle);
|
||||
+ cy.wrap(body).contains(expectedTitle);
|
||||
|
||||
// back button should not exist on the home page, whose title is the default value
|
||||
if (expectedTitle === 'User Skills'){
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/package.json b/skills-client-integration/skills-int-e2e-test/package.json
|
||||
index 8664332..7209ea6 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/package.json
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/package.json
|
||||
@@ -38,7 +38,7 @@
|
||||
"dev:removeNpmLinks": "mvn --batch-mode clean package && java -cp target/skills-int-e2e-test-*.jar -Dloader.main=skills.RemoveNpmLinks org.springframework.boot.loader.PropertiesLauncher"
|
||||
},
|
||||
"devDependencies": {
|
||||
- "cypress": "4.1.0",
|
||||
+ "cypress": "6.2.0",
|
||||
"license-check-and-add": "3.0.4",
|
||||
"license-checker": "25.0.1",
|
||||
"semver": "7.1.2",
|
||||
+184
@@ -1,3 +1,23 @@
|
||||
diff --git a/skills-client-integration/skills-int-client-ng/package.json b/skills-client-integration/skills-int-client-ng/package.json
|
||||
index 2b35e51..04e41c8 100644
|
||||
--- a/skills-client-integration/skills-int-client-ng/package.json
|
||||
+++ b/skills-client-integration/skills-int-client-ng/package.json
|
||||
@@ -34,7 +34,7 @@
|
||||
"bootstrap": "4.5.0",
|
||||
"jquery": "3.5.1",
|
||||
"js-beautify": "1.10.2",
|
||||
- "ngx-highlightjs": "4.1.0-beta",
|
||||
+ "ngx-highlightjs": "4.1.3",
|
||||
"rxjs": "6.5.5",
|
||||
"tslib": "2.0.0",
|
||||
"zone.js": "0.10.3"
|
||||
@@ -61,4 +61,4 @@
|
||||
"tslint": "6.1.0",
|
||||
"typescript": "3.9.5"
|
||||
}
|
||||
-}
|
||||
\ No newline at end of file
|
||||
+}
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress.json b/skills-client-integration/skills-int-e2e-test/cypress.json
|
||||
index 52f9451..a87626c 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress.json
|
||||
@@ -14,3 +34,167 @@ index 52f9451..a87626c 100644
|
||||
+ "openMode": 0
|
||||
+ }
|
||||
}
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
index 4c944c8..b17b00d 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
@@ -207,7 +207,7 @@ context('Angular Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -221,7 +221,7 @@ context('Angular Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -240,7 +240,7 @@ context('Angular Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - summary only', () => {
|
||||
@@ -257,7 +257,7 @@ context('Angular Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
index 4b4dd85..f3cb810 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
@@ -115,7 +115,7 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it("skill display - default options", () => {
|
||||
@@ -137,7 +137,7 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it("skill display - summary only", () => {
|
||||
@@ -159,7 +159,7 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it("skill display - theme", () => {
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
index 5c51e84..c64f0b8 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
@@ -150,7 +150,7 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - summary only', () => {
|
||||
@@ -167,7 +167,7 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
index 2544edf..0b035f5 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
@@ -207,7 +207,7 @@ context('Vue Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -221,7 +221,7 @@ context('Vue Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -240,7 +240,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('Proxy Skills Display', () => {
|
||||
@@ -262,7 +262,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
cy.visit('/vuejs#/proxyShowSkills')
|
||||
@@ -287,7 +287,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
@@ -409,7 +409,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});*!/
|
||||
})*/
|
||||
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js b/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
index e899916..4761ae5 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
@@ -173,7 +173,7 @@ Cypress.Commands.add("cdClickSubj", (subjIndex, expectedTitle) => {
|
||||
|
||||
Cypress.Commands.add("cdBack", (expectedTitle = 'User Skills') => {
|
||||
cy.wrapIframe().find('[data-cy=back]').click()
|
||||
- cy.wrapIframe().find('h2').contains(expectedTitle);
|
||||
+ cy.wrapIframe().contains(expectedTitle);
|
||||
|
||||
// back button should not exist on the home page, whose title is the default value
|
||||
if (expectedTitle === 'User Skills'){
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
index 393ec38..ace542b 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
@@ -207,7 +207,7 @@ context('Angular Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -221,7 +221,7 @@ context('Angular Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -240,7 +240,7 @@ context('Angular Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - summary only', () => {
|
||||
@@ -257,7 +257,7 @@ context('Angular Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
index a82b1a6..e951f9c 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
@@ -116,7 +116,7 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it("skill display - default options", () => {
|
||||
@@ -138,7 +138,7 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it("skill display - summary only", () => {
|
||||
@@ -160,7 +160,7 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it("skill display - theme", () => {
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
index 38151c4..5a95fbe 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
@@ -150,7 +150,7 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - summary only', () => {
|
||||
@@ -167,7 +167,7 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
index d861deb..4037779 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
@@ -207,7 +207,7 @@ context('Vue Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -221,7 +221,7 @@ context('Vue Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -240,7 +240,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('Proxy Skills Display', () => {
|
||||
@@ -261,7 +261,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
|
||||
cy.visit('/vuejs#/proxyShowSkills')
|
||||
cy.wait('@getToken2')
|
||||
@@ -284,7 +284,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
@@ -407,7 +407,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});*!/
|
||||
})*/
|
||||
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js b/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
index 48da2de..d66fb30 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
@@ -182,7 +182,7 @@ Cypress.Commands.add("cdClickSubj", (subjIndex, expectedTitle) => {
|
||||
|
||||
Cypress.Commands.add("cdBack", (expectedTitle = 'User Skills') => {
|
||||
cy.wrapIframe().find('[data-cy=back]').click()
|
||||
- cy.wrapIframe().find('h2').contains(expectedTitle);
|
||||
+ cy.wrapIframe().contains(expectedTitle);
|
||||
|
||||
// back button should not exist on the home page, whose title is the default value
|
||||
if (expectedTitle === 'User Skills') {
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
index 393ec38..ace542b 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/angular.specs.js
|
||||
@@ -207,7 +207,7 @@ context('Angular Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -221,7 +221,7 @@ context('Angular Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -240,7 +240,7 @@ context('Angular Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - summary only', () => {
|
||||
@@ -257,7 +257,7 @@ context('Angular Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
index a82b1a6..e951f9c 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/js.specs.js
|
||||
@@ -116,7 +116,7 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it("skill display - default options", () => {
|
||||
@@ -138,7 +138,7 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it("skill display - summary only", () => {
|
||||
@@ -160,7 +160,7 @@ context("Native JS Tests", () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it("skill display - theme", () => {
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
index 38151c4..5a95fbe 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/react.specs.js
|
||||
@@ -150,7 +150,7 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - summary only', () => {
|
||||
@@ -167,7 +167,7 @@ context('React Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js b/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
index d861deb..4037779 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/integration/vue.specs.js
|
||||
@@ -207,7 +207,7 @@ context('Vue Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithButton button').click()
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -221,7 +221,7 @@ context('Vue Tests', () => {
|
||||
cy.get('#SkillsDirectiveErrorwithInput input').type('h')
|
||||
cy.wait('@postSkill');
|
||||
cy.get('@postSkill').then((xhr) => {
|
||||
- expect(xhr.status).to.eq(400)
|
||||
+ expect(xhr.status).to.eq(404)
|
||||
expect(xhr.responseBody).to.have.property('explanation').to.eq('Failed to report skill event because skill definition does not exist.')
|
||||
});
|
||||
})
|
||||
@@ -240,7 +240,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('Proxy Skills Display', () => {
|
||||
@@ -261,7 +261,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
|
||||
cy.visit('/vuejs#/proxyShowSkills')
|
||||
cy.wait('@getToken2')
|
||||
@@ -284,7 +284,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrapIframe().find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
})
|
||||
|
||||
it('skill display - theme', () => {
|
||||
@@ -407,7 +407,7 @@ context('Vue Tests', () => {
|
||||
// verify that there is no background set
|
||||
// cypress always validates against rgb
|
||||
cy.wrap(body).find('.skills-page-title-text-color')
|
||||
- .should('have.css', 'background-color').and('equal', 'rgb(255, 255, 255)');
|
||||
+ .should('have.css', 'background-color').and('equal', 'rgba(0, 0, 0, 0)');
|
||||
});*!/
|
||||
})*/
|
||||
|
||||
diff --git a/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js b/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
index d32ca41..d66fb30 100644
|
||||
--- a/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
+++ b/skills-client-integration/skills-int-e2e-test/cypress/support/commands.js
|
||||
@@ -182,7 +182,7 @@ Cypress.Commands.add("cdClickSubj", (subjIndex, expectedTitle) => {
|
||||
|
||||
Cypress.Commands.add("cdBack", (expectedTitle = 'User Skills') => {
|
||||
cy.wrapIframe().find('[data-cy=back]').click()
|
||||
- cy.wrapIframe().find('[data-cy=title]').contains(expectedTitle);
|
||||
+ cy.wrapIframe().contains(expectedTitle);
|
||||
|
||||
// back button should not exist on the home page, whose title is the default value
|
||||
if (expectedTitle === 'User Skills') {
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<version>3.1.1-SNAPSHOT</version>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skills-int-service</artifactId>
|
||||
<description>SkillTree Client Lib Integration Tests</description>
|
||||
|
||||
+6
@@ -52,6 +52,8 @@ public class SkillsExampleApplication implements WebMvcConfigurer {
|
||||
String password;
|
||||
@JsonIgnore
|
||||
String authMode = "token";
|
||||
String proxiedProjectId;
|
||||
String proxiedUserId;
|
||||
|
||||
public String getServiceUrl() { return serviceUrl; }
|
||||
public String getProjectId() { return projectId; }
|
||||
@@ -59,6 +61,8 @@ public class SkillsExampleApplication implements WebMvcConfigurer {
|
||||
public String getUsername() { return username; }
|
||||
public String getPassword() { return password; }
|
||||
public String getAuthMode() { return authMode; }
|
||||
public String getProxiedProjectId() { return proxiedProjectId; }
|
||||
public String getProxiedUserId() { return proxiedUserId; }
|
||||
|
||||
public void setServiceUrl(String serviceUrl) { this.serviceUrl = serviceUrl; }
|
||||
public void setProjectId(String projectId) { this.projectId = projectId; }
|
||||
@@ -66,5 +70,7 @@ public class SkillsExampleApplication implements WebMvcConfigurer {
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
public void setPassword(String password) { this.password = password; }
|
||||
public void setAuthMode(String authMode) { this.authMode = authMode; }
|
||||
public void setProxiedProjectId(String proxiedProjectId) { this.proxiedProjectId = proxiedProjectId; }
|
||||
public void setProxiedUserId(String proxiedUserId) { this.proxiedUserId = proxiedUserId; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
const presets = [
|
||||
[
|
||||
"@babel/env",
|
||||
],
|
||||
];
|
||||
|
||||
module.exports = { presets };
|
||||
module.exports = {
|
||||
presets: ['@babel/preset-env'],
|
||||
plugins: ['@babel/plugin-transform-runtime'],
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@skilltree/skills-client-js",
|
||||
"version": "3.1.1",
|
||||
"version": "3.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib - Native JS Lib",
|
||||
"main": "dist/skills-client-js.umd.min.js",
|
||||
@@ -24,6 +24,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.11.6",
|
||||
"@babel/core": "7.11.6",
|
||||
"@babel/plugin-transform-runtime": "7.13.10",
|
||||
"@babel/polyfill": "7.11.5",
|
||||
"@babel/preset-env": "7.11.5",
|
||||
"@rollup/plugin-commonjs": "15.1.0",
|
||||
@@ -46,6 +47,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "0.21.1",
|
||||
"history": "5.0.0",
|
||||
"js-logger": "1.6.0",
|
||||
"postmate": "1.5.2",
|
||||
"sockjs-client": "1.5.0",
|
||||
|
||||
@@ -17,6 +17,7 @@ module.exports = {
|
||||
plugins: [
|
||||
eslint(),
|
||||
babel({
|
||||
runtimeHelpers: true,
|
||||
exclude: 'node_modules/**',
|
||||
}),
|
||||
resolve({
|
||||
|
||||
@@ -96,10 +96,10 @@ export default {
|
||||
},
|
||||
|
||||
isOAuthMode(authenticator, serviceUrl) {
|
||||
return typeof authenticator === 'string' && (authenticator === 'oauth' || authenticator.startsWith(`${serviceUrl}/oauth2/authorization`));
|
||||
return typeof authenticator === 'string' && authenticator.startsWith(`${serviceUrl}/oauth2/authorization`);
|
||||
},
|
||||
|
||||
getAuthenticationToken(authenticator, serviceUrl, projectId) {
|
||||
getAuthenticationToken(authenticator, serviceUrl, projectId, oauthRedirect = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const isOAuthMode = this.isOAuthMode(authenticator, serviceUrl);
|
||||
const xhr = new XMLHttpRequest();
|
||||
@@ -113,11 +113,12 @@ export default {
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status !== 200) {
|
||||
if (isOAuthMode && xhr.status === 401) {
|
||||
if (isOAuthMode && oauthRedirect && xhr.status === 401) {
|
||||
// if we get 401 and we are using OAuth, then redirect to the OAuth Provider
|
||||
const oauthAuthenticator = `${authenticator}?skillsRedirectUri=${window.location}`;
|
||||
log.info(`SkillsClient::SkillService::unable to get oAuth token, navigating to [${oauthAuthenticator}]`);
|
||||
window.location = oauthAuthenticator;
|
||||
window.location.assign(oauthAuthenticator);
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(`SkillTree: Unable to authenticate using [${authenticator}] endpoint. Response Code=[${xhr.status}].\n
|
||||
Ideas to diagnose:\n
|
||||
|
||||
@@ -65,7 +65,12 @@ const exportObject = {
|
||||
projectId,
|
||||
authenticator,
|
||||
authToken,
|
||||
oauthRedirect = false,
|
||||
}) {
|
||||
if (this.isInitialized()) {
|
||||
log.warn('SkillsConfiguration already initialized.');
|
||||
return;
|
||||
}
|
||||
if (!this.skillsClientVersion) {
|
||||
// this will be replaced at build time with the current skills-client-js
|
||||
// version. extensions of the plain JS client (vue, react, etc), should
|
||||
@@ -96,7 +101,7 @@ const exportObject = {
|
||||
}
|
||||
|
||||
if (!this.isPKIMode() && !this.getAuthToken()) {
|
||||
skillsService.getAuthenticationToken(this.getAuthenticator(), this.getServiceUrl(), this.getProjectId())
|
||||
skillsService.getAuthenticationToken(this.getAuthenticator(), this.getServiceUrl(), this.getProjectId(), oauthRedirect)
|
||||
.then((token) => {
|
||||
this.setAuthToken(token);
|
||||
setInitialized(this);
|
||||
@@ -109,8 +114,8 @@ const exportObject = {
|
||||
}).catch((error) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Error getting service status', error);
|
||||
setInitialized(this);
|
||||
setConfigureWasCalled();
|
||||
initializedResolvers.resolve();
|
||||
});
|
||||
},
|
||||
|
||||
@@ -170,6 +175,8 @@ SkillsConfiguration is a singleton and you only have to do this once. Please see
|
||||
logout() {
|
||||
initializedResolvers = null;
|
||||
waitForInitializePromise = null;
|
||||
configureCalled = false;
|
||||
initialized = false;
|
||||
initializeAfterConfigurePromise();
|
||||
this.setAuthToken(null);
|
||||
},
|
||||
|
||||
@@ -15,21 +15,28 @@
|
||||
*/
|
||||
import Postmate from 'postmate';
|
||||
import log from 'js-logger';
|
||||
import { createBrowserHistory } from 'history';
|
||||
|
||||
import SkillsConfiguration from '../config/SkillsConfiguration';
|
||||
import ErrorPageUtils from './ErrorPageUtils';
|
||||
import skillsService from '../SkillsService';
|
||||
|
||||
let uniqueId = 0;
|
||||
let history = null; // createBrowserHistory();
|
||||
let unlisten = () => {};
|
||||
|
||||
const skillsClientDisplayPath = 'skillsClientDisplayPath';
|
||||
const POP = 'POP';
|
||||
|
||||
export default class SkillsDisplayJS {
|
||||
/* eslint-disable object-curly-newline */
|
||||
constructor({ options, theme, version, userId } = {}) {
|
||||
constructor({ options, theme, version, handleRouteChanged, userId } = {}) {
|
||||
log.debug(`SkillsClient::SkillsDisplayJS::Constructing with options [${options}], theme [${theme}], version [${version}], userId [${userId}]`);
|
||||
this._validateOptions(options);
|
||||
this._options = { ...{ }, ...options };
|
||||
this._theme = theme;
|
||||
this._version = version;
|
||||
this._handleRouteChanged = handleRouteChanged;
|
||||
this._userId = userId;
|
||||
}
|
||||
|
||||
@@ -65,6 +72,7 @@ export default class SkillsDisplayJS {
|
||||
theme: this.theme,
|
||||
minHeight: `${minHeight}px`,
|
||||
isSummaryOnly: this.options.isSummaryOnly,
|
||||
internalBackButton: this.options.internalBackButton == null ? false : this.options.internalBackButton,
|
||||
},
|
||||
});
|
||||
const iframe = document.querySelector(`.${className}`);
|
||||
@@ -73,6 +81,19 @@ export default class SkillsDisplayJS {
|
||||
iframeContainer.height = 0;
|
||||
iframeContainer.style.height = '0px';
|
||||
|
||||
const updateChildRoute = (previousLocation = this.skillsDisplayPath, skipParentHistory = true, replace = true) => {
|
||||
if (this._childFrame && !(previousLocation == null)) {
|
||||
this._childFrame.call('navigate', { path: previousLocation, replace, query: { skipParentHistory } });
|
||||
}
|
||||
};
|
||||
history = createBrowserHistory();
|
||||
// Listen for changes to the current location from the back/forward browser buttons.
|
||||
unlisten = history.listen(({ action }) => {
|
||||
if (action === POP) {
|
||||
updateChildRoute(this.skillsDisplayPath || '/', true);
|
||||
}
|
||||
});
|
||||
|
||||
handshake.then((child) => {
|
||||
this._childFrame = child;
|
||||
child.on('height-changed', (data) => {
|
||||
@@ -81,8 +102,26 @@ export default class SkillsDisplayJS {
|
||||
iframeContainer.height = adjustedHeight;
|
||||
iframeContainer.style.height = `${adjustedHeight}px`;
|
||||
});
|
||||
child.on('route-changed', () => {
|
||||
log.debug('SkillsClient::SkillsDisplayJS::route-changed');
|
||||
child.on('route-changed', (params) => {
|
||||
const newPath = params ? params.path : null;
|
||||
log.debug(`SkillsClient::SkillsDisplayJS::route-changed - newPath [${newPath}]`);
|
||||
if (!(newPath == null)) {
|
||||
const routePath = newPath.endsWith('index.html') ? '/' : newPath;
|
||||
if (this._shouldUpdateHistory(params)) {
|
||||
// put the new path in the URL so that when the page is reloaded or
|
||||
// sent as a link the proper route will be set in the child iframe
|
||||
const queryParams = new URLSearchParams(window.location.search);
|
||||
queryParams.set(skillsClientDisplayPath, routePath);
|
||||
const newUrl = `${window.location.pathname}?${queryParams.toString()}${window.location.hash}`;
|
||||
history.push(newUrl, { skillsClientDisplayPath: newPath });
|
||||
}
|
||||
|
||||
// if the client has configured a handleRouteChanged call back, invoke it
|
||||
if (this._handleRouteChanged) {
|
||||
this._handleRouteChanged(routePath);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.options.disableAutoScroll) {
|
||||
let scrollToElement = iframeContainer;
|
||||
|
||||
@@ -110,12 +149,14 @@ export default class SkillsDisplayJS {
|
||||
this.authenticationPromise = skillsService.getAuthenticationToken(this.configuration.authenticator, this.configuration.serviceUrl, this.configuration.projectId)
|
||||
.then((result) => {
|
||||
child.call('updateAuthenticationToken', result);
|
||||
updateChildRoute();
|
||||
})
|
||||
.finally(() => {
|
||||
this.authenticationPromise = null;
|
||||
});
|
||||
} else if (isPkiMode) {
|
||||
child.call('updateAuthenticationToken', 'pki');
|
||||
updateChildRoute();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -147,6 +188,14 @@ export default class SkillsDisplayJS {
|
||||
}
|
||||
}
|
||||
|
||||
_shouldUpdateHistory(params) {
|
||||
// if the query param `skipParentHistory` is true then do not update the history (set to true when the user is navigating with the back/forward browser buttons)
|
||||
const updateHistoryParam = (params.query.skipParentHistory !== 'true' && params.query.skipParentHistory !== true);
|
||||
// also, allow the client app to disable this feature, but enable it by default
|
||||
const updateHistoryOption = this.options.updateHistory == null || this.options.updateHistory === true;
|
||||
return updateHistoryOption && updateHistoryParam;
|
||||
}
|
||||
|
||||
set version(version) {
|
||||
log.info(`SkillsClient::SkillsDisplayJS::setting version [${version}]`);
|
||||
this._version = version;
|
||||
@@ -176,6 +225,12 @@ export default class SkillsDisplayJS {
|
||||
return { serviceUrl, authenticator, projectId };
|
||||
}
|
||||
|
||||
get skillsDisplayPath() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const clientDisplayPath = urlParams.get(skillsClientDisplayPath);
|
||||
return clientDisplayPath;
|
||||
}
|
||||
|
||||
_validateOptions(options) {
|
||||
const configOptions = [
|
||||
'authenticator',
|
||||
@@ -185,6 +240,8 @@ export default class SkillsDisplayJS {
|
||||
'autoScrollStrategy',
|
||||
'isSummaryOnly',
|
||||
'scrollTopOffset',
|
||||
'internalBackButton',
|
||||
'updateHistory',
|
||||
];
|
||||
const toTest = { ...this._options, ...options };
|
||||
const passedOptions = Object.keys(toTest);
|
||||
@@ -199,5 +256,8 @@ export default class SkillsDisplayJS {
|
||||
if (this._childFrame) {
|
||||
this._childFrame.destroy();
|
||||
}
|
||||
const queryParams = new URLSearchParams(window.location.search);
|
||||
queryParams.delete(skillsClientDisplayPath);
|
||||
unlisten();
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,15 @@ const FAILURE_EVENT = 'skills-report-error';
|
||||
const successHandlerCache = new Set();
|
||||
const errorHandlerCache = new Set();
|
||||
|
||||
let retryIntervalId = null;
|
||||
|
||||
const callSuccessHandlers = (event) => {
|
||||
successHandlerCache.forEach((it) => it(event));
|
||||
};
|
||||
|
||||
const callErrorHandlers = (event) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Error reporting skill:', event);
|
||||
errorHandlerCache.forEach((it) => it(event));
|
||||
};
|
||||
|
||||
@@ -61,6 +65,43 @@ const connectWebsocket = (serviceUrl) => {
|
||||
}
|
||||
};
|
||||
|
||||
const retryQueueKey = 'skillTreeRetryQueue';
|
||||
const defaultMaxRetryQueueSize = 1000;
|
||||
const defaultRetryInterval = 60000;
|
||||
const defaultMaxRetryAttempts = 1440;
|
||||
const retryErrors = function retryErrors() {
|
||||
const retryQueue = JSON.parse(localStorage.getItem(retryQueueKey));
|
||||
localStorage.removeItem(retryQueueKey);
|
||||
if (retryQueue !== null) {
|
||||
retryQueue.forEach((item) => {
|
||||
log.info(`SkillsClient::SkillsReporter::retryErrors retrying skillId [${item.skillId}], timestamp [${item.timestamp}], retryAttempt [${item.retryAttempt}]`);
|
||||
this.reportSkill(item.skillId, 0, item.timestamp, true, item.retryAttempt);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const addToRetryQueue = (skillId, timeReported, retryAttempt, xhr, maxQueueSize) => {
|
||||
log.info(`SkillsClient::SkillsReporter::addToRetryQueue [${skillId}], timeReported [${timeReported}], retryAttempt[${retryAttempt}], status [${xhr.status}]`);
|
||||
if (xhr.response) {
|
||||
const xhrResponse = JSON.parse(xhr.response);
|
||||
if (xhrResponse && xhrResponse.errorCode === 'SkillNotFound') {
|
||||
log.info('not adding to retry queue because the skillId does not exist.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
let retryQueue = JSON.parse(localStorage.getItem(retryQueueKey));
|
||||
if (retryQueue == null) {
|
||||
retryQueue = [];
|
||||
}
|
||||
if (retryQueue.length < maxQueueSize) {
|
||||
const timestamp = (timeReported == null) ? Date.now() : timeReported;
|
||||
retryQueue.push({ skillId, timestamp, retryAttempt });
|
||||
localStorage.setItem(retryQueueKey, JSON.stringify(retryQueue));
|
||||
} else {
|
||||
log.warn(`Max retry queue size has been reached (${maxQueueSize}), Unable to retry skillId [${skillId}]`);
|
||||
}
|
||||
};
|
||||
|
||||
const authenticateAndRetry = function authenticateAndRetry(userSkillId, attemptCount, resolve, reject) {
|
||||
log.info(`SkillsClient::SkillsReporter::authenticateAndRetry [${userSkillId}] attemptCount [${attemptCount}]`);
|
||||
skillsService.getAuthenticationToken(SkillsConfiguration.getAuthenticator(), SkillsConfiguration.getServiceUrl(), SkillsConfiguration.getProjectId())
|
||||
@@ -81,9 +122,12 @@ const authenticateAndRetry = function authenticateAndRetry(userSkillId, attemptC
|
||||
|
||||
const SkillsReporter = {
|
||||
configure({
|
||||
notifyIfSkillNotApplied,
|
||||
notifyIfSkillNotApplied, retryInterval = defaultRetryInterval, maxRetryQueueSize = defaultMaxRetryQueueSize, maxRetryAttempts = defaultMaxRetryAttempts,
|
||||
}) {
|
||||
this.notifyIfSkillNotApplied = notifyIfSkillNotApplied;
|
||||
this.retryInterval = retryInterval;
|
||||
this.maxRetryQueueSize = maxRetryQueueSize;
|
||||
this.maxRetryAttempts = maxRetryAttempts;
|
||||
},
|
||||
|
||||
addSuccessHandler(handler) {
|
||||
@@ -101,9 +145,14 @@ const SkillsReporter = {
|
||||
errorHandlerCache.add(handler);
|
||||
log.info(`SkillsClient::SkillsReporter::added error handler [${handler ? handler.toString() : handler}]`);
|
||||
},
|
||||
reportSkill(userSkillId, count = undefined) {
|
||||
reportSkill(userSkillId, count = undefined, timestamp = null, isRetry = false, retryAttempt = undefined) {
|
||||
log.info(`SkillsClient::SkillsReporter::reporting skill [${userSkillId}] count [${count}]`);
|
||||
SkillsConfiguration.validate();
|
||||
if (!this.retryEnabled) {
|
||||
log.info('SkillsClient::SkillsReporter::Enabling retries...');
|
||||
retryIntervalId = setInterval(() => { retryErrors.call(this); }, this.retryInterval || defaultRetryInterval);
|
||||
this.retryEnabled = true;
|
||||
}
|
||||
if (count >= 25) {
|
||||
const errorMessage = 'Unable to authenticate after 25 attempts';
|
||||
log.error(`SkillsReporter::${errorMessage}`);
|
||||
@@ -115,6 +164,11 @@ const SkillsReporter = {
|
||||
countInternal = count;
|
||||
}
|
||||
|
||||
let retryAttemptInternal = 1;
|
||||
if (retryAttempt !== undefined) {
|
||||
retryAttemptInternal = retryAttempt + 1;
|
||||
}
|
||||
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
if (!SkillsConfiguration.getAuthToken() && !SkillsConfiguration.isPKIMode()) {
|
||||
authenticateAndRetry.call(this, userSkillId, countInternal, resolve, reject);
|
||||
@@ -130,9 +184,20 @@ const SkillsReporter = {
|
||||
xhr.onreadystatechange = () => {
|
||||
// some browsers don't understand XMLHttpRequest.Done, which should be 4
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status !== 200 && xhr.status !== 0 && xhr.status !== 401) {
|
||||
reject(JSON.parse(xhr.response));
|
||||
} else if ((xhr.status === 401 || xhr.status === 0) && !SkillsConfiguration.isPKIMode()) {
|
||||
if (xhr.status !== 200 && xhr.status !== 401) {
|
||||
const maxRetryAttempts = this.maxRetryAttempts || defaultMaxRetryAttempts;
|
||||
const maxRetryQueueSize = this.maxRetryQueueSize || defaultMaxRetryQueueSize;
|
||||
if (retryAttemptInternal <= maxRetryAttempts) {
|
||||
addToRetryQueue(userSkillId, timestamp, retryAttemptInternal, xhr, maxRetryQueueSize);
|
||||
} else {
|
||||
log.warn(`Max retry attempts has been reached (${this.maxRetryAttempts}), Unable to retry skillId [${userSkillId}]`);
|
||||
}
|
||||
if (xhr.response) {
|
||||
reject(JSON.parse(xhr.response));
|
||||
} else {
|
||||
reject(new Error(`Error occurred reporting skill [${userSkillId}], status returned [${xhr.status}]`));
|
||||
}
|
||||
} else if ((xhr.status === 401) && !SkillsConfiguration.isPKIMode()) {
|
||||
authenticateAndRetry.call(this, userSkillId, countInternal, resolve, reject);
|
||||
} else {
|
||||
resolve(JSON.parse(xhr.response));
|
||||
@@ -140,15 +205,10 @@ const SkillsReporter = {
|
||||
}
|
||||
};
|
||||
|
||||
if (this.notifyIfSkillNotApplied) {
|
||||
const body = JSON.stringify({ notifyIfSkillNotApplied: this.notifyIfSkillNotApplied });
|
||||
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
|
||||
xhr.send(body);
|
||||
log.info('SkillsClient::SkillsReporter::reporting skill request sent with notifyIfSkillNotApplied=true');
|
||||
} else {
|
||||
xhr.send();
|
||||
log.info('SkillsClient::SkillsReporter::reporting skill request sent with notifyIfSkillNotApplied=false');
|
||||
}
|
||||
const body = JSON.stringify({ timestamp, notifyIfSkillNotApplied: this.notifyIfSkillNotApplied, isRetry });
|
||||
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
|
||||
xhr.send(body);
|
||||
log.info(`SkillsClient::SkillsReporter::reporting skill request sent: ${body}`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -162,6 +222,12 @@ const SkillsReporter = {
|
||||
getConf() {
|
||||
return SkillsConfiguration;
|
||||
},
|
||||
|
||||
cancelRetryChecker() {
|
||||
clearInterval(retryIntervalId);
|
||||
this.retryEnabled = false;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2020 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import mock from 'xhr-mock';
|
||||
import SkillsService from '../src/SkillsService';
|
||||
|
||||
require('@babel/polyfill');
|
||||
|
||||
describe('OAuth auto redirect tests', () => {
|
||||
const mockServiceUrl = 'http://some.com';
|
||||
const mockProjectId = 'proj1';
|
||||
const authEndpoint = `${mockServiceUrl}/oauth2/authorization/gitlab`;
|
||||
const oldWindowLocation = window.location
|
||||
|
||||
beforeAll(() => {
|
||||
delete window.location
|
||||
|
||||
window.location = Object.defineProperties(
|
||||
{},
|
||||
{
|
||||
...Object.getOwnPropertyDescriptors(oldWindowLocation),
|
||||
assign: {
|
||||
configurable: true,
|
||||
value: jest.fn(),
|
||||
},
|
||||
},
|
||||
)
|
||||
})
|
||||
afterAll(() => {
|
||||
// restore `window.location` to the `jsdom` `Location` object
|
||||
window.location = oldWindowLocation
|
||||
})
|
||||
|
||||
// replace the real XHR object with the mock XHR object before each test
|
||||
beforeEach(() => {
|
||||
mock.setup();
|
||||
const url = /.*\/api\/projects\/proj1\/skillsClientVersion/;
|
||||
window.location.assign.mockReset()
|
||||
});
|
||||
|
||||
// put the real XHR object back and clear the mocks after each test
|
||||
afterEach(() => {
|
||||
mock.teardown();
|
||||
});
|
||||
|
||||
it('oauth auto redirects when oauthRedirect=true', async () => {
|
||||
const oauthTokenEndpoint = `${mockServiceUrl}/api/projects/${mockProjectId}/token`;
|
||||
mock.get(oauthTokenEndpoint, (req, res) => res.status(401));
|
||||
|
||||
await SkillsService.getAuthenticationToken(authEndpoint, mockServiceUrl, mockProjectId, true);
|
||||
|
||||
expect(window.location.assign).toHaveBeenCalledTimes(1)
|
||||
expect(window.location.assign).toHaveBeenCalledWith(`${authEndpoint}?skillsRedirectUri=http://localhost/`)
|
||||
});
|
||||
|
||||
it('oauth does not auto redirect when oauthRedirect=false', async () => {
|
||||
const oauthTokenEndpoint = `${mockServiceUrl}/api/projects/${mockProjectId}/token`;
|
||||
mock.get(oauthTokenEndpoint, (req, res) => res.status(401));
|
||||
|
||||
try {
|
||||
await SkillsService.getAuthenticationToken(authEndpoint, mockServiceUrl, mockProjectId);
|
||||
} catch (e) {
|
||||
expect(e.message).toMatch('Unable to authenticate');
|
||||
expect(window.location.assign).toHaveBeenCalledTimes(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('oauth does not auto redirect when oauthRedirect=true but token is returned', async () => {
|
||||
const oauthTokenEndpoint = `${mockServiceUrl}/api/projects/${mockProjectId}/token`;
|
||||
mock.get(oauthTokenEndpoint, (req, res) => res.status(200).body('{"access_token": "token1"}'));
|
||||
|
||||
const result = await SkillsService.getAuthenticationToken(authEndpoint, mockServiceUrl, mockProjectId, true);
|
||||
expect(window.location.assign).toHaveBeenCalledTimes(0);
|
||||
expect(result).toMatch('token1');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -17,19 +17,28 @@ import mock from 'xhr-mock';
|
||||
import SkillsConfiguration from '../../src/config/SkillsConfiguration';
|
||||
|
||||
describe('SkillsConfiguration', () => {
|
||||
const flushPromises = () => new Promise(setImmediate);
|
||||
const mockStatusResponse = '{"status":"OK","clientLib":{"loggingEnabled":"false","loggingLevel":"DEBUG"}}';
|
||||
const mockVersionResponse = '{"success":true,"explanation":null}';
|
||||
let statusReqCount = 0;
|
||||
|
||||
// replace the real XHR object with the mock XHR object before each test
|
||||
beforeEach(() => {
|
||||
mock.setup();
|
||||
SkillsConfiguration.logout();
|
||||
const url = /.*\/api\/projects\/.*\/skillsClientVersion/;
|
||||
mock.post(url, (req, res) => res.status(200).body('{"success":true,"explanation":null}'));
|
||||
mock.get(/.*\/public\/status/, (req, res) => res.status(200).body('{"status":"OK","clientLib":{"loggingEnabled":"false","loggingLevel":"DEBUG"}}'));
|
||||
mock.post(url, (req, res) => res.status(200).body(mockVersionResponse));
|
||||
mock.get(/.*\/public\/status/, (req, res) => {
|
||||
statusReqCount++;
|
||||
return res.status(200).body(mockStatusResponse);
|
||||
});
|
||||
});
|
||||
|
||||
// put the real XHR object back and clear the mocks after each test
|
||||
afterEach(() => {
|
||||
SkillsConfiguration.logout();
|
||||
mock.teardown();
|
||||
statusReqCount = 0;
|
||||
});
|
||||
|
||||
describe('initialization', () => {
|
||||
@@ -43,9 +52,79 @@ describe('SkillsConfiguration', () => {
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('setAuthToken updates the authToken', () => {
|
||||
it('isInitialized is false when error occurs in configure', () => {
|
||||
expect(() => {
|
||||
SkillsConfiguration.configure({
|
||||
serviceUrl: 'http://somewhere',
|
||||
authenticator: 'pki',
|
||||
});
|
||||
|
||||
// when an error occurs during initialization isInitialized should be false, but wasConfigureCalled should be true
|
||||
expect(SkillsConfiguration.isInitialized()).toBe(false);
|
||||
expect(SkillsConfiguration.wasConfigureCalled()).toBe(true);
|
||||
expect(statusReqCount).toBe(1);
|
||||
}).toThrow('SkillTree: SkillsConfiguration.configure received invalid parameter for projectId=[undefined]');
|
||||
});
|
||||
|
||||
it('calling configure more than once after failure will attempt to configure again', async () => {
|
||||
expect.assertions(6);
|
||||
|
||||
mock.reset();
|
||||
mock.get(/.*\/public\/status/, (req, res) => {
|
||||
statusReqCount++;
|
||||
return res.status(503);
|
||||
});
|
||||
const mockAuthenticator = Math.random().toString();
|
||||
mock.get(mockAuthenticator, (req, res) => res.status(200).body('{"access_token": "token"}'));
|
||||
|
||||
const config = {
|
||||
projectId: Math.random().toString(),
|
||||
serviceUrl: Math.random().toString(),
|
||||
authenticator: mockAuthenticator,
|
||||
authToken: Math.random().toString(),
|
||||
};
|
||||
|
||||
SkillsConfiguration.configure(config);
|
||||
await flushPromises();
|
||||
expect(SkillsConfiguration.isInitialized()).toBe(false);
|
||||
expect(SkillsConfiguration.wasConfigureCalled()).toBe(true);
|
||||
expect(statusReqCount).toBe(1);
|
||||
|
||||
SkillsConfiguration.configure(config);
|
||||
await flushPromises();
|
||||
expect(SkillsConfiguration.isInitialized()).toBe(false);
|
||||
expect(SkillsConfiguration.wasConfigureCalled()).toBe(true);
|
||||
expect(statusReqCount).toBe(2);
|
||||
});
|
||||
|
||||
it('calling configure more than once without failure will NOT attempt to configure again', async () => {
|
||||
expect.assertions(6);
|
||||
const mockAuthenticator = Math.random().toString();
|
||||
mock.get(mockAuthenticator, (req, res) => res.status(200).body('{"access_token": "token"}'));
|
||||
const config = {
|
||||
projectId: Math.random().toString(),
|
||||
serviceUrl: Math.random().toString(),
|
||||
authenticator: mockAuthenticator,
|
||||
authToken: Math.random().toString(),
|
||||
};
|
||||
|
||||
SkillsConfiguration.configure(config);
|
||||
await flushPromises();
|
||||
expect(SkillsConfiguration.isInitialized()).toBe(true);
|
||||
expect(SkillsConfiguration.wasConfigureCalled()).toBe(true);
|
||||
expect(statusReqCount).toBe(1);
|
||||
|
||||
SkillsConfiguration.configure(config);
|
||||
await flushPromises();
|
||||
expect(SkillsConfiguration.isInitialized()).toBe(true);
|
||||
expect(SkillsConfiguration.wasConfigureCalled()).toBe(true);
|
||||
expect(statusReqCount).toBe(1);
|
||||
});
|
||||
|
||||
it('setAuthToken updates the authToken', async () => {
|
||||
const mockAuthToken = Math.random() + 1;
|
||||
SkillsConfiguration.configure({ authToken: mockAuthToken, projectId: 'projectId', serviceUrl: 'http://somewhere' });
|
||||
await flushPromises();
|
||||
|
||||
expect(SkillsConfiguration.getAuthToken()).toBe(mockAuthToken);
|
||||
|
||||
@@ -57,32 +136,36 @@ describe('SkillsConfiguration', () => {
|
||||
|
||||
describe('initializing', () => {
|
||||
describe('isPKIMode', () => {
|
||||
it('isPKIMode is false if authenticator is NOT \'pki\'', () => {
|
||||
it('isPKIMode is false if authenticator is NOT \'pki\'', async () => {
|
||||
const mockAuthenticator = Math.random().toString();
|
||||
|
||||
mock.get(mockAuthenticator, (req, res) => res.status(200).body('{"access_token": "token"}'));
|
||||
SkillsConfiguration.configure({
|
||||
authenticator: mockAuthenticator, projectId: 'proj', serviceUrl: 'http://somewhere',
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
expect(SkillsConfiguration.isPKIMode()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('isPKIMode is true if authenticator is \'pki\'', () => {
|
||||
it('isPKIMode is true if authenticator is \'pki\'', async () => {
|
||||
const mockAuthenticator = 'pki';
|
||||
|
||||
SkillsConfiguration.configure({
|
||||
authenticator: mockAuthenticator, projectId: 'proj', serviceUrl: 'http://somewhere',
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
expect(SkillsConfiguration.isPKIMode()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it('properly initializes variables', () => {
|
||||
const mockServiceUrl = Math.random().toString();;
|
||||
const mockProjectId = Math.random().toString();;
|
||||
const mockAuthenticator = Math.random().toString();;
|
||||
const mockAuthToken = Math.random().toString();;
|
||||
it('properly initializes variables', async () => {
|
||||
expect.assertions(6);
|
||||
|
||||
const mockServiceUrl = Math.random().toString();
|
||||
const mockProjectId = Math.random().toString();
|
||||
const mockAuthenticator = Math.random().toString();
|
||||
const mockAuthToken = Math.random().toString();
|
||||
|
||||
SkillsConfiguration.configure({
|
||||
projectId: mockProjectId,
|
||||
@@ -90,14 +173,17 @@ describe('SkillsConfiguration', () => {
|
||||
authenticator: mockAuthenticator,
|
||||
authToken: mockAuthToken,
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
expect(SkillsConfiguration.getProjectId()).toBe(mockProjectId);
|
||||
expect(SkillsConfiguration.getServiceUrl()).toBe(mockServiceUrl);
|
||||
expect(SkillsConfiguration.getAuthenticator()).toBe(mockAuthenticator);
|
||||
expect(SkillsConfiguration.getAuthToken()).toBe(mockAuthToken);
|
||||
expect(SkillsConfiguration.isInitialized()).toBe(true);
|
||||
expect(SkillsConfiguration.wasConfigureCalled()).toBe(true);
|
||||
});
|
||||
|
||||
it('notifies afterConfigure Promisees' ,(done) => {
|
||||
it('notifies afterConfigure Promisees', (done) => {
|
||||
let resolveCount = 0;
|
||||
SkillsConfiguration.afterConfigure().then(() => {
|
||||
resolveCount++;
|
||||
@@ -112,12 +198,15 @@ describe('SkillsConfiguration', () => {
|
||||
SkillsConfiguration.configure({ authenticator: 'pki', projectId: 'proj', serviceUrl: 'http://somewhere' });
|
||||
});
|
||||
|
||||
it('trailing slash and spaces are removed from the serviceUrl', () => {
|
||||
it('trailing slash and spaces are removed from the serviceUrl', async () => {
|
||||
const authEndpoint = 'http://auth/';
|
||||
mock.get(authEndpoint, (req, res) => res.status(200).body('{"access_token": "token"}'));
|
||||
SkillsConfiguration.configure({
|
||||
projectId: 'proj',
|
||||
serviceUrl: ' http://some/ ',
|
||||
authenticator: 'http://auth',
|
||||
authenticator: authEndpoint,
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
expect(SkillsConfiguration.getServiceUrl()).toBe('http://some');
|
||||
});
|
||||
@@ -130,6 +219,10 @@ describe('SkillsConfiguration', () => {
|
||||
serviceUrl: 'http://somewhere',
|
||||
authenticator: 'pki',
|
||||
});
|
||||
|
||||
// when an error occurs during initialization isInitialized should be false, but wasConfigureCalled should be true
|
||||
expect(SkillsConfiguration.isInitialized()).toBe(false);
|
||||
expect(SkillsConfiguration.wasConfigureCalled()).toBe(true);
|
||||
}).toThrow('SkillTree: SkillsConfiguration.configure received invalid parameter for projectId=[undefined]');
|
||||
});
|
||||
|
||||
@@ -162,7 +255,6 @@ describe('SkillsConfiguration', () => {
|
||||
}).toThrow('SkillTree: SkillsConfiguration.configure received invalid parameter for serviceUrl=[undefined]');
|
||||
});
|
||||
|
||||
|
||||
it('throws an error if authenticator is set to null', () => {
|
||||
expect(() => {
|
||||
SkillsConfiguration.configure({
|
||||
@@ -212,7 +304,7 @@ describe('SkillsConfiguration', () => {
|
||||
expect(oldPromise).not.toBe(newPromise);
|
||||
});
|
||||
|
||||
it('clears the authToken', () => {
|
||||
it('clears the authToken', async () => {
|
||||
const mockAuthToken = Math.random().toString();;
|
||||
SkillsConfiguration.configure({
|
||||
authToken: mockAuthToken,
|
||||
@@ -220,6 +312,7 @@ describe('SkillsConfiguration', () => {
|
||||
serviceUrl: 'http://some',
|
||||
authenticator: 'http://auth',
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
expect(SkillsConfiguration.getAuthToken()).toBe(mockAuthToken);
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ describe('SkillsDisplayJS', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('rout-changed event', () => {
|
||||
describe('route-changed event', () => {
|
||||
it('does not attempt to scroll if disableAutoScroll option is set', (done) => {
|
||||
const client = new SkillsDisplayJS({
|
||||
options: {
|
||||
@@ -223,7 +223,7 @@ describe('SkillsDisplayJS', () => {
|
||||
client.attachTo(mockIframeContainer);
|
||||
|
||||
setTimeout(() => {
|
||||
mockChildFrame.emit('route-changed');
|
||||
mockChildFrame.emit('route-changed', { path: 'blah', query: {} });
|
||||
expect(mockIframeContainer.scrollIntoView).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
@@ -245,7 +245,7 @@ describe('SkillsDisplayJS', () => {
|
||||
client.attachTo(mockIframeContainer);
|
||||
|
||||
setTimeout(() => {
|
||||
mockChildFrame.emit('route-changed');
|
||||
mockChildFrame.emit('route-changed', { path: 'blah', query: {} });
|
||||
expect(mockIframeContainer.scrollIntoView).toHaveBeenCalledWith({ behavior: 'smooth' });
|
||||
done();
|
||||
});
|
||||
@@ -268,7 +268,7 @@ describe('SkillsDisplayJS', () => {
|
||||
const top = mockIframeContainer.offsetTop - 10;
|
||||
|
||||
setTimeout(() => {
|
||||
mockChildFrame.emit('route-changed');
|
||||
mockChildFrame.emit('route-changed', { path: 'blah', query: {} });
|
||||
expect(global.scroll).toHaveBeenCalledWith({ top, behavior: 'smooth' });
|
||||
done();
|
||||
});
|
||||
@@ -298,11 +298,37 @@ describe('SkillsDisplayJS', () => {
|
||||
client.attachTo(mockIframeContainer);
|
||||
|
||||
setTimeout(() => {
|
||||
mockChildFrame.emit('route-changed');
|
||||
mockChildFrame.emit('route-changed', { path: 'blah', query: {} });
|
||||
expect(mockBody.scrollIntoView).toHaveBeenCalledWith({ behavior: 'smooth' });
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('handles null params', (done) => {
|
||||
const client = new SkillsDisplayJS({
|
||||
options: {
|
||||
disableAutoScroll: true,
|
||||
}
|
||||
});
|
||||
|
||||
const mockIframeContainer = {
|
||||
setAttribute: jest.fn(),
|
||||
style: {},
|
||||
scrollIntoView: jest.fn(),
|
||||
};
|
||||
|
||||
global.document.querySelector = () => {
|
||||
return mockIframeContainer;
|
||||
};
|
||||
|
||||
client.attachTo(mockIframeContainer);
|
||||
|
||||
setTimeout(() => {
|
||||
mockChildFrame.emit('route-changed');
|
||||
expect(mockIframeContainer.scrollIntoView).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('needs-authentication event', () => {
|
||||
@@ -437,6 +463,7 @@ describe('SkillsDisplayJS', () => {
|
||||
theme: mockTheme,
|
||||
minHeight: '960px',
|
||||
isSummaryOnly: false,
|
||||
internalBackButton: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -473,6 +500,120 @@ describe('SkillsDisplayJS', () => {
|
||||
theme: mockTheme,
|
||||
minHeight: '600px',
|
||||
isSummaryOnly: true,
|
||||
internalBackButton: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
it('properly configures Postmate internalBackButton === false when set explicitly', () => {
|
||||
const client = new SkillsDisplayJS({
|
||||
options: {
|
||||
isSummaryOnly: true,
|
||||
authenticator: mockAuthenticator,
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
internalBackButton: false,
|
||||
},
|
||||
theme: mockTheme,
|
||||
version: mockVersion,
|
||||
});
|
||||
const mockIframeContainer = {
|
||||
setAttribute: jest.fn(),
|
||||
style: { },
|
||||
};
|
||||
|
||||
global.document.querySelector = () => { return mockIframeContainer; };
|
||||
|
||||
client.attachTo(mockIframeContainer);
|
||||
|
||||
expect(Postmate).toHaveBeenCalledWith({
|
||||
container: mockIframeContainer,
|
||||
url: `${mockServiceUrl}/static/clientPortal/index.html`,
|
||||
classListArray: [`client-display-iframe-${client.currentIframeId()}`],
|
||||
model: {
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
version: mockVersion,
|
||||
userId: null,
|
||||
theme: mockTheme,
|
||||
minHeight: '600px',
|
||||
isSummaryOnly: true,
|
||||
internalBackButton: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('properly configures Postmate internalBackButton === true when set explicitly', () => {
|
||||
const client = new SkillsDisplayJS({
|
||||
options: {
|
||||
isSummaryOnly: true,
|
||||
authenticator: mockAuthenticator,
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
internalBackButton: true,
|
||||
},
|
||||
theme: mockTheme,
|
||||
version: mockVersion,
|
||||
});
|
||||
const mockIframeContainer = {
|
||||
setAttribute: jest.fn(),
|
||||
style: { },
|
||||
};
|
||||
|
||||
global.document.querySelector = () => { return mockIframeContainer; };
|
||||
|
||||
client.attachTo(mockIframeContainer);
|
||||
|
||||
expect(Postmate).toHaveBeenCalledWith({
|
||||
container: mockIframeContainer,
|
||||
url: `${mockServiceUrl}/static/clientPortal/index.html`,
|
||||
classListArray: [`client-display-iframe-${client.currentIframeId()}`],
|
||||
model: {
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
version: mockVersion,
|
||||
userId: null,
|
||||
theme: mockTheme,
|
||||
minHeight: '600px',
|
||||
isSummaryOnly: true,
|
||||
internalBackButton: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('properly configures Postmate internalBackButton === false when NOT set explicitly', () => {
|
||||
const client = new SkillsDisplayJS({
|
||||
options: {
|
||||
isSummaryOnly: true,
|
||||
authenticator: mockAuthenticator,
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
},
|
||||
theme: mockTheme,
|
||||
version: mockVersion,
|
||||
});
|
||||
const mockIframeContainer = {
|
||||
setAttribute: jest.fn(),
|
||||
style: { },
|
||||
};
|
||||
|
||||
global.document.querySelector = () => { return mockIframeContainer; };
|
||||
|
||||
client.attachTo(mockIframeContainer);
|
||||
|
||||
expect(Postmate).toHaveBeenCalledWith({
|
||||
container: mockIframeContainer,
|
||||
url: `${mockServiceUrl}/static/clientPortal/index.html`,
|
||||
classListArray: [`client-display-iframe-${client.currentIframeId()}`],
|
||||
model: {
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
version: mockVersion,
|
||||
userId: null,
|
||||
theme: mockTheme,
|
||||
minHeight: '600px',
|
||||
isSummaryOnly: true,
|
||||
internalBackButton: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright 2020 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import mock from 'xhr-mock';
|
||||
import SkillsConfiguration from '../../src/config/SkillsConfiguration';
|
||||
import { SkillsReporter } from '../../src/reporter/SkillsReporter';
|
||||
|
||||
require('@babel/polyfill');
|
||||
|
||||
describe('retryTests()', () => {
|
||||
const mockServiceUrl = 'http://some.com';
|
||||
const mockProjectId = 'proj1';
|
||||
const authEndpoint = `${mockServiceUrl}/auth/endpoint`;
|
||||
const flushPromises = () => new Promise(setImmediate);
|
||||
|
||||
// replace the real XHR object with the mock XHR object before each test
|
||||
beforeEach(() => {
|
||||
mock.setup();
|
||||
SkillsConfiguration.logout();
|
||||
SkillsReporter.configure({ retryInterval: 60 });
|
||||
const url = /.*\/api\/projects\/proj1\/skillsClientVersion/;
|
||||
mock.post(url, (req, res) => res.status(200).body('{"success":true,"explanation":null}'));
|
||||
mock.get(/.*\/public\/status/, (req, res) => res.status(200).body('{"status":"OK","clientLib":{"loggingEnabled":"false","loggingLevel":"DEBUG"}}'));
|
||||
});
|
||||
|
||||
// put the real XHR object back and clear the mocks after each test
|
||||
afterEach(() => {
|
||||
SkillsReporter.cancelRetryChecker();
|
||||
window.localStorage.removeItem('skillTreeRetryQueue');
|
||||
SkillsConfiguration.logout();
|
||||
mock.teardown();
|
||||
});
|
||||
|
||||
it('reportSkill will retry for errors', async () => {
|
||||
expect.assertions(8);
|
||||
const mockUserSkillId = 'skill1-random';
|
||||
|
||||
mock.get(authEndpoint, (req, res) => res.status(200).body('{"access_token": "token"}'));
|
||||
SkillsConfiguration.configure({
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
authenticator: authEndpoint,
|
||||
});
|
||||
await flushPromises();
|
||||
const handler1 = jest.fn();
|
||||
const mockSuccess = '{"data":{"id":"abc-123"}}';
|
||||
const mockError = JSON.stringify({
|
||||
explanation: 'Some random error occurred.', errorCode: 'RandomError', success: false, projectId: 'movies', skillId: 'IronMan', userId: 'user1',
|
||||
});
|
||||
let body = mockError;
|
||||
let status = 503;
|
||||
|
||||
SkillsReporter.addErrorHandler(handler1);
|
||||
|
||||
const url = `${mockServiceUrl}/api/projects/${mockProjectId}/skills/${mockUserSkillId}`;
|
||||
let count = 0;
|
||||
let timestamp = null;
|
||||
mock.post(url, (req, res) => {
|
||||
expect(req.header('Authorization')).toEqual('Bearer token');
|
||||
count++;
|
||||
if (count > 1) {
|
||||
const reqBody = JSON.parse(req.body());
|
||||
expect(reqBody.isRetry).toEqual(true); // verify that isRetry is set to true
|
||||
if (timestamp == null) {
|
||||
timestamp = reqBody.timestamp;
|
||||
} else {
|
||||
expect(timestamp).toEqual(reqBody.timestamp); // verify the timestamp remains the same
|
||||
}
|
||||
}
|
||||
|
||||
// fail the first two times, then succeed after that
|
||||
if (count > 2) {
|
||||
body = mockSuccess;
|
||||
status = 200;
|
||||
}
|
||||
return res.status(status).body(body);
|
||||
});
|
||||
|
||||
try {
|
||||
await SkillsReporter.reportSkill(mockUserSkillId);
|
||||
} catch (e) {
|
||||
}
|
||||
// sleep for 3 seconds
|
||||
await new Promise((r) => setTimeout(r, 3000));
|
||||
expect(count).toEqual(3);
|
||||
expect(handler1).toHaveBeenCalledWith(JSON.parse(mockError));
|
||||
});
|
||||
|
||||
it('reportSkill will not retry on success', async () => {
|
||||
expect.assertions(4);
|
||||
const mockUserSkillId = 'skill1-success';
|
||||
|
||||
mock.get(authEndpoint, (req, res) => res.status(200).body('{"access_token": "token"}'));
|
||||
SkillsConfiguration.configure({
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
authenticator: authEndpoint,
|
||||
});
|
||||
await flushPromises();
|
||||
const handler1 = jest.fn();
|
||||
|
||||
SkillsReporter.addErrorHandler(handler1);
|
||||
|
||||
const url = `${mockServiceUrl}/api/projects/${mockProjectId}/skills/${mockUserSkillId}`;
|
||||
let count = 0;
|
||||
mock.post(url, (req, res) => {
|
||||
expect(req.header('Authorization')).toEqual('Bearer token');
|
||||
count++;
|
||||
return res.status(200).body('{"data":{"id":"abc-123"}}');
|
||||
});
|
||||
|
||||
const res = await SkillsReporter.reportSkill(mockUserSkillId);
|
||||
// sleep for 2 seconds
|
||||
await new Promise((r) => setTimeout(r, 2000));
|
||||
expect(res).toEqual({ data: { id: 'abc-123' } });
|
||||
expect(count).toEqual(1);
|
||||
expect(handler1).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('do not exceed the max retry queue size', async () => {
|
||||
const maxRetryQueueSize = 2;
|
||||
SkillsReporter.configure({ maxRetryQueueSize });
|
||||
|
||||
mock.get(authEndpoint, (req, res) => res.status(200).body('{"access_token": "token"}'));
|
||||
SkillsConfiguration.configure({
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
authenticator: authEndpoint,
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
const mockError = JSON.stringify({
|
||||
explanation: 'Some random error occurred - maxRetryQueueSize.', errorCode: 'RandomError', success: false, projectId: 'movies', skillId: 'IronMan', userId: 'user1',
|
||||
});
|
||||
const url = /.*\/api\/projects\/proj1\/skills\/skill[1-3]/;
|
||||
mock.post(url, (req, res) => {
|
||||
expect(req.header('Authorization')).toEqual('Bearer token');
|
||||
return res.status(503).body(mockError);
|
||||
});
|
||||
try { await SkillsReporter.reportSkill('skill1'); } catch (e) { }
|
||||
try { await SkillsReporter.reportSkill('skill2'); } catch (e) { }
|
||||
try { await SkillsReporter.reportSkill('skill3'); } catch (e) { }
|
||||
|
||||
const retryQueue = JSON.parse(window.localStorage.getItem('skillTreeRetryQueue'));
|
||||
expect(retryQueue.length).toEqual(maxRetryQueueSize);
|
||||
expect(retryQueue.find((item) => item.skillId === 'skill1')).toBeTruthy();
|
||||
expect(retryQueue.find((item) => item.skillId === 'skill2')).toBeTruthy();
|
||||
expect(retryQueue.find((item) => item.skillId === 'skill3')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('do not exceed the max retry attempts size', async () => {
|
||||
const maxRetryAttempts = 2;
|
||||
SkillsReporter.configure({ retryInterval: 60, maxRetryAttempts });
|
||||
|
||||
mock.get(authEndpoint, (req, res) => res.status(200).body('{"access_token": "token"}'));
|
||||
SkillsConfiguration.configure({
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
authenticator: authEndpoint,
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
const handler1 = jest.fn();
|
||||
SkillsReporter.addErrorHandler(handler1);
|
||||
const mockUserSkillId = 'skill1-random';
|
||||
const mockError = JSON.stringify({
|
||||
explanation: 'Some random error occurred - maxRetryAttempts.', errorCode: 'RandomError', success: false, projectId: 'movies', skillId: 'IronMan', userId: 'user1',
|
||||
});
|
||||
const url = `${mockServiceUrl}/api/projects/${mockProjectId}/skills/${mockUserSkillId}`;
|
||||
let count = 0;
|
||||
let timestamp = null;
|
||||
mock.post(url, (req, res) => {
|
||||
expect(req.header('Authorization')).toEqual('Bearer token');
|
||||
count++;
|
||||
if (count > 1) {
|
||||
const reqBody = JSON.parse(req.body());
|
||||
expect(reqBody.isRetry).toEqual(true); // verify that isRetry is set to true
|
||||
if (timestamp == null) {
|
||||
timestamp = reqBody.timestamp;
|
||||
} else {
|
||||
expect(timestamp).toEqual(reqBody.timestamp); // verify the timestamp remains the same
|
||||
}
|
||||
}
|
||||
return res.status(503).body(mockError);
|
||||
});
|
||||
|
||||
try {
|
||||
await SkillsReporter.reportSkill(mockUserSkillId);
|
||||
} catch (e) {
|
||||
}
|
||||
// sleep for 3 seconds
|
||||
await new Promise((r) => setTimeout(r, 3000));
|
||||
expect(count).toEqual(maxRetryAttempts + 1); // initial attempt plus 2 retries
|
||||
expect(handler1).toHaveBeenCalledWith(JSON.parse(mockError));
|
||||
|
||||
const retryQueue = JSON.parse(window.localStorage.getItem('skillTreeRetryQueue'));
|
||||
expect(retryQueue).toBeNull();
|
||||
});
|
||||
|
||||
it('reportSkill will not retry when errorCode === SkillNotFound', async () => {
|
||||
SkillsConfiguration.logout();
|
||||
expect.assertions(3);
|
||||
const mockUserSkillId = 'skill1-SkillNotFound';
|
||||
|
||||
mock.get(authEndpoint, (req, res) => res.status(200).body('{"access_token": "token"}'));
|
||||
SkillsConfiguration.configure({
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
authenticator: authEndpoint,
|
||||
});
|
||||
await flushPromises();
|
||||
const handler1 = jest.fn();
|
||||
const mockError = JSON.stringify({
|
||||
explanation: 'Failed to report skill event because skill definition does not exist.', errorCode: 'SkillNotFound', success: false, projectId: 'movies', skillId: 'DoesNotExist', userId: 'user1',
|
||||
});
|
||||
const body = mockError;
|
||||
const status = 503;
|
||||
|
||||
SkillsReporter.addErrorHandler(handler1);
|
||||
|
||||
const url = `${mockServiceUrl}/api/projects/${mockProjectId}/skills/${mockUserSkillId}`;
|
||||
let count = 0;
|
||||
mock.post(url, (req, res) => {
|
||||
expect(req.header('Authorization')).toEqual('Bearer token');
|
||||
count++;
|
||||
return res.status(status).body(body);
|
||||
});
|
||||
|
||||
try {
|
||||
await SkillsReporter.reportSkill(mockUserSkillId);
|
||||
} catch (e) {
|
||||
}
|
||||
// sleep for 3 seconds
|
||||
await new Promise((r) => setTimeout(r, 3000));
|
||||
expect(count).toEqual(1);
|
||||
expect(handler1).toHaveBeenCalledWith(JSON.parse(mockError));
|
||||
});
|
||||
|
||||
|
||||
it('reportSkill will retry for errors when maxRetryAttempts is undefined', async () => {
|
||||
SkillsReporter.maxRetryAttempts = undefined;
|
||||
expect.assertions(8);
|
||||
const mockUserSkillId = 'skill1-random';
|
||||
|
||||
mock.get(authEndpoint, (req, res) => res.status(200).body('{"access_token": "token"}'));
|
||||
SkillsConfiguration.configure({
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
authenticator: authEndpoint,
|
||||
});
|
||||
await flushPromises();
|
||||
const handler1 = jest.fn();
|
||||
const mockSuccess = '{"data":{"id":"abc-123"}}';
|
||||
const mockError = JSON.stringify({
|
||||
explanation: 'Some random error occurred.', errorCode: 'RandomError', success: false, projectId: 'movies', skillId: 'IronMan', userId: 'user1',
|
||||
});
|
||||
let body = mockError;
|
||||
let status = 503;
|
||||
|
||||
SkillsReporter.addErrorHandler(handler1);
|
||||
|
||||
const url = `${mockServiceUrl}/api/projects/${mockProjectId}/skills/${mockUserSkillId}`;
|
||||
let count = 0;
|
||||
let timestamp = null;
|
||||
mock.post(url, (req, res) => {
|
||||
expect(req.header('Authorization')).toEqual('Bearer token');
|
||||
count++;
|
||||
if (count > 1) {
|
||||
const reqBody = JSON.parse(req.body());
|
||||
expect(reqBody.isRetry).toEqual(true); // verify that isRetry is set to true
|
||||
if (timestamp == null) {
|
||||
timestamp = reqBody.timestamp;
|
||||
} else {
|
||||
expect(timestamp).toEqual(reqBody.timestamp); // verify the timestamp remains the same
|
||||
}
|
||||
}
|
||||
|
||||
// fail the first two times, then succeed after that
|
||||
if (count > 2) {
|
||||
body = mockSuccess;
|
||||
status = 200;
|
||||
}
|
||||
return res.status(status).body(body);
|
||||
});
|
||||
|
||||
try {
|
||||
await SkillsReporter.reportSkill(mockUserSkillId);
|
||||
} catch (e) {
|
||||
}
|
||||
// sleep for 3 seconds
|
||||
await new Promise((r) => setTimeout(r, 3000));
|
||||
expect(count).toEqual(3);
|
||||
expect(handler1).toHaveBeenCalledWith(JSON.parse(mockError));
|
||||
});
|
||||
});
|
||||
@@ -100,9 +100,7 @@ describe('userSkillsService', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
MockXMLHttpRequest.status = 200;
|
||||
mockResponse = JSON.stringify({
|
||||
hello: 'world',
|
||||
});
|
||||
mockResponse = JSON.stringify({"success":true,"projectId":"movies","skillId":"IronMan","name":"Iron Man","pointsEarned":8,"skillApplied":true,"explanation":"Skill event was applied","completed":[]});
|
||||
MockXMLHttpRequest.response = mockResponse;
|
||||
promise = SkillsReporter.reportSkill(mockUserSkillId);
|
||||
});
|
||||
@@ -141,9 +139,7 @@ describe('userSkillsService', () => {
|
||||
beforeEach(() => {
|
||||
MockXMLHttpRequest.status = 404;
|
||||
promise = SkillsReporter.reportSkill(mockUserSkillId);
|
||||
mockError = JSON.stringify({
|
||||
you: 'errored',
|
||||
});
|
||||
mockError = JSON.stringify({"explanation":"Failed to report skill event because skill definition does not exist.","errorCode":"SkillNotFound","success":false,"projectId":"movies","skillId":"DoesNotExist","userId":"user1"});
|
||||
MockXMLHttpRequest.response = mockError;
|
||||
});
|
||||
|
||||
@@ -159,6 +155,7 @@ describe('userSkillsService', () => {
|
||||
it('calls error handlers', (done) => {
|
||||
const handler1 = jest.fn();
|
||||
const handler2 = jest.fn();
|
||||
const consoleSpy = jest.spyOn(console, 'error');
|
||||
|
||||
SkillsReporter.addErrorHandler(handler1);
|
||||
SkillsReporter.addErrorHandler(handler2);
|
||||
@@ -168,6 +165,7 @@ describe('userSkillsService', () => {
|
||||
promise.finally(() => {
|
||||
expect(handler1).toHaveBeenCalledWith(JSON.parse(mockError));
|
||||
expect(handler2).toHaveBeenCalledWith(JSON.parse(mockError));
|
||||
expect(consoleSpy).toHaveBeenCalledWith('Error reporting skill:', JSON.parse(mockError));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "skills-client-ng-parent",
|
||||
"version": "3.1.1",
|
||||
"version": "3.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib - Angular",
|
||||
"author": "SkillTree Team",
|
||||
@@ -27,8 +27,8 @@
|
||||
"@angular/platform-browser": "10.1.5",
|
||||
"@angular/platform-browser-dynamic": "10.1.5",
|
||||
"@angular/router": "10.1.5",
|
||||
"@skilltree/skills-client-js": "3.1.1",
|
||||
"lodash-es": "4.17.15",
|
||||
"@skilltree/skills-client-js": "3.3.0",
|
||||
"lodash-es": "4.17.21",
|
||||
"rxjs": "6.6.3",
|
||||
"tslib": "2.0.3",
|
||||
"zone.js": "0.11.1"
|
||||
@@ -40,7 +40,7 @@
|
||||
"@angular/compiler-cli": "10.1.5",
|
||||
"@types/jasmine": "3.5.14",
|
||||
"@types/jasminewd2": "2.0.8",
|
||||
"@types/lodash-es": "4.17.3",
|
||||
"@types/lodash-es": "4.17.4",
|
||||
"@types/node": "14.11.8",
|
||||
"codelyzer": "6.0.1",
|
||||
"jasmine-core": "3.6.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@skilltree/skills-client-ng",
|
||||
"version": "3.1.1",
|
||||
"version": "3.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib - Angular",
|
||||
"author": "SkillTree Team",
|
||||
@@ -8,12 +8,12 @@
|
||||
"prepare": "node -e \"console.log('APP_VERSION = \\''+ process.env.npm_package_name + '-' + process.env.npm_package_version +'\\';')\" > src/version.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "10.0.4",
|
||||
"@angular/core": "10.0.4"
|
||||
"@angular/common": "10.1.5",
|
||||
"@angular/core": "10.1.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "2.0.0",
|
||||
"@skilltree/skills-client-js": "3.1.1"
|
||||
"@skilltree/skills-client-js": "3.3.0"
|
||||
},
|
||||
"keywords": [
|
||||
"SkillTree",
|
||||
|
||||
+2
@@ -32,6 +32,7 @@ export class SkillsDisplayComponent implements OnInit, OnDestroy {
|
||||
@Input() version: number;
|
||||
@Input() theme: string;
|
||||
@Input() userId: string;
|
||||
@Input() handleRouteChanged: Function;
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
@@ -40,6 +41,7 @@ export class SkillsDisplayComponent implements OnInit, OnDestroy {
|
||||
version: this.version,
|
||||
theme: this.theme,
|
||||
userId: this.userId,
|
||||
handleRouteChanged: this.handleRouteChanged,
|
||||
});
|
||||
this.clientDisplay.attachTo(document.getElementById('clientDisplayContainer'));
|
||||
}
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"],
|
||||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"env": {
|
||||
"test": {
|
||||
"presets": [["@babel/preset-env", { "targets": { "node": "current" } }]]
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"node": "current"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@skilltree/skills-client-react",
|
||||
"version": "3.1.1",
|
||||
"version": "3.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib - React",
|
||||
"main": "dist/skills-client-react.umd.min.js",
|
||||
@@ -25,9 +25,9 @@
|
||||
},
|
||||
"author": "SkillTree Team",
|
||||
"peerDependencies": {
|
||||
"prop-types": "15.X",
|
||||
"react": "16.X",
|
||||
"react-dom": "16.X",
|
||||
"prop-types": "15.X"
|
||||
"react-dom": "16.X"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.11.6",
|
||||
@@ -38,7 +38,10 @@
|
||||
"@rollup/plugin-commonjs": "15.1.0",
|
||||
"@rollup/plugin-node-resolve": "9.0.0",
|
||||
"@rollup/plugin-replace": "2.3.3",
|
||||
"babel-eslint": "10.1.0",
|
||||
"eslint-config-airbnb-base": "14.2.0",
|
||||
"eslint-plugin-react": "7.21.4",
|
||||
"eslint-plugin-react-hooks": "4.1.2",
|
||||
"license-check-and-add": "3.0.4",
|
||||
"license-checker": "25.0.1",
|
||||
"react": "16.13.1",
|
||||
@@ -50,16 +53,12 @@
|
||||
"rollup-plugin-eslint": "7.0.0",
|
||||
"rollup-plugin-json": "4.0.0",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.0",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
"rollup-plugin-uglify": "6.0.4",
|
||||
"eslint-plugin-react-hooks": "4.1.2",
|
||||
"babel-eslint": "10.1.0",
|
||||
"eslint-plugin-react": "7.21.4"
|
||||
"rollup-plugin-terser": "7.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@skilltree/skills-client-js": "3.1.1",
|
||||
"@skilltree/skills-client-js": "3.3.0",
|
||||
"axios": "0.21.1",
|
||||
"axios-auth-refresh": "3.0.0"
|
||||
"axios-auth-refresh": "3.1.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { SkillsDisplayJS } from '@skilltree/skills-client-js';
|
||||
import PropTypes from 'prop-types';
|
||||
import './SkillsDisplay.css';
|
||||
@@ -24,14 +24,16 @@ const destroy = (cd) => {
|
||||
cd.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
// eslint-disable-next-line object-curly-newline
|
||||
const SkillDisplay = ({ theme = null, version = null, userId = null, options = {} }) => {
|
||||
React.useEffect(() => {
|
||||
const SkillDisplay = ({ theme = null, version = null, userId = null, handleRouteChanged = null, options = {} }) => {
|
||||
useEffect(() => {
|
||||
clientDisplay = new SkillsDisplayJS({
|
||||
options,
|
||||
theme,
|
||||
version,
|
||||
userId,
|
||||
handleRouteChanged,
|
||||
});
|
||||
|
||||
clientDisplay.attachTo(document.getElementById('clientSkillsDisplayContainer'));
|
||||
@@ -39,7 +41,7 @@ const SkillDisplay = ({ theme = null, version = null, userId = null, options = {
|
||||
return () => {
|
||||
destroy(clientDisplay);
|
||||
};
|
||||
}, [theme, version, userId, options]);
|
||||
}, [theme, version, userId, handleRouteChanged, options]);
|
||||
|
||||
return (<div id='clientSkillsDisplayContainer'/>);
|
||||
};
|
||||
@@ -48,12 +50,15 @@ SkillDisplay.propTypes = {
|
||||
theme: PropTypes.object,
|
||||
version: PropTypes.string,
|
||||
userId: PropTypes.string,
|
||||
handleRouteChanged: PropTypes.func,
|
||||
options: PropTypes.shape({
|
||||
serviceUrl: PropTypes.string,
|
||||
projectId: PropTypes.string,
|
||||
disableAutoScroll: PropTypes.bool,
|
||||
autoScrollStrategy: PropTypes.string,
|
||||
isSummaryOnly: PropTypes.bool,
|
||||
internalBackButton: PropTypes.bool,
|
||||
updateHistory: PropTypes.bool,
|
||||
scrollTopOffset: PropTypes.number,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
|
||||
import { SkillsLevelJS } from '@skilltree/skills-client-js';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// eslint-disable-next-line object-curly-newline
|
||||
const SkillsLevel = ({ projectId }) => {
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const skillLevel = new SkillsLevelJS(projectId);
|
||||
skillLevel.attachTo('.skills-level-text-display');
|
||||
}, [projectId]);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@skilltree/skills-client-vue",
|
||||
"version": "3.1.1",
|
||||
"version": "3.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib - Vue.js",
|
||||
"main": "dist/skills-client-vue.umd.min.js",
|
||||
@@ -24,13 +24,13 @@
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.11.6",
|
||||
"@babel/preset-env": "7.11.5",
|
||||
"babel-eslint": "10.1.0",
|
||||
"@rollup/plugin-alias": "3.1.1",
|
||||
"@rollup/plugin-commonjs": "15.1.0",
|
||||
"@rollup/plugin-node-resolve": "9.0.0",
|
||||
"@rollup/plugin-replace": "2.3.3",
|
||||
"@vue/test-utils": "1.1.0",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-jest": "26.5.2",
|
||||
"eslint-config-airbnb-base": "14.2.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
@@ -45,18 +45,17 @@
|
||||
"rollup-plugin-json": "4.0.0",
|
||||
"rollup-plugin-peer-deps-external": "2.2.3",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
"rollup-plugin-uglify": "6.0.4",
|
||||
"rollup-plugin-vue": "5.1.9",
|
||||
"vue": "2.6.12",
|
||||
"vue-eslint-parser": "7.1.1",
|
||||
"vue-jest": "3.0.7",
|
||||
"vue-template-compiler": "2.6.12",
|
||||
"vue-eslint-parser": "7.1.1"
|
||||
"vue-template-compiler": "2.6.12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@skilltree/skills-client-js": "3.1.1",
|
||||
"@skilltree/skills-client-js": "3.3.0",
|
||||
"axios": "0.21.1",
|
||||
"axios-auth-refresh": "3.0.0",
|
||||
"lodash": "4.17.20",
|
||||
"axios-auth-refresh": "3.1.0",
|
||||
"lodash": "4.17.21",
|
||||
"postmate": "1.5.2"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -38,6 +38,8 @@ limitations under the License.
|
||||
'autoScrollStrategy',
|
||||
'isSummaryOnly',
|
||||
'scrollTopOffset',
|
||||
'internalBackButton',
|
||||
'updateHistory,',
|
||||
];
|
||||
const options = { ...defaults, ...value };
|
||||
const passedOptions = Object.keys(options);
|
||||
@@ -72,6 +74,7 @@ limitations under the License.
|
||||
version: this.version,
|
||||
theme: this.theme,
|
||||
userId: this.userId,
|
||||
handleRouteChanged: (newPath) => { this.$emit('route-changed', newPath); },
|
||||
});
|
||||
Logger.info(`SkillsDisplay::created SkillsDisplayJS...calling attachTo for ref [${this.$refs.clientDisplayContainer}]`);
|
||||
this.clientDisplay.attachTo(this.$refs.clientDisplayContainer);
|
||||
|
||||
Reference in new issue
Block a user