mirror of
https://github.com/NationalSecurityAgency/skills-client.git
synced 2026-11-07 06:05:59 -10:00
Compare commits
83
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1925c31934 | ||
|
|
48ff8e052c | ||
|
|
037009f8a8 | ||
|
|
dca695d685 | ||
|
|
24905e9a42 | ||
|
|
5a98e7fd2c | ||
|
|
897d1b9b1c | ||
|
|
3a5bcc1f04 | ||
|
|
030a8bd24a | ||
|
|
532f33a8a7 | ||
|
|
b070e4058e | ||
|
|
6b1ba358d8 | ||
|
|
e845fb7788 | ||
|
|
599e838086 | ||
|
|
ad5ab89439 | ||
|
|
3c408f555f | ||
|
|
ea523e9381 | ||
|
|
cea08a3dd5 | ||
|
|
731853a8a6 | ||
|
|
78c338fd36 | ||
|
|
80052f77ac | ||
|
|
b4e7718741 | ||
|
|
42c40ce92f | ||
|
|
18ad1af38e | ||
|
|
58f6265836 | ||
|
|
e3f299376c | ||
|
|
2b66377a30 | ||
|
|
b88c19d0c7 | ||
|
|
558cecacdd | ||
|
|
dbcc95f951 | ||
|
|
50ac5c413f | ||
|
|
cf0961c435 | ||
|
|
56cb884fdb | ||
|
|
6af2944841 | ||
|
|
a301650700 | ||
|
|
d19947c814 | ||
|
|
361bae4289 | ||
|
|
aae9cc7ee9 | ||
|
|
60c3d5edb1 | ||
|
|
bb12395d80 | ||
|
|
dea819670b | ||
|
|
7553782dcc | ||
|
|
daf5b1fca8 | ||
|
|
83878d8c3a | ||
|
|
83178bf58b | ||
|
|
03cf175e26 | ||
|
|
04c9f2e950 | ||
|
|
3f952ba966 | ||
|
|
b7ad03fb64 | ||
|
|
39c7abc757 | ||
|
|
aa0af7e776 | ||
|
|
33cfff5ebb | ||
|
|
7efe886ef4 | ||
|
|
caa236dff1 | ||
|
|
2b5b28c8dc | ||
|
|
481a6d0505 | ||
|
|
5103989eef | ||
|
|
266bf9911d | ||
|
|
8ab6ab5a3a | ||
|
|
d747c2b96f | ||
|
|
002ab3f783 | ||
|
|
a5f3848c16 | ||
|
|
601c7a2a96 | ||
|
|
8fcc10d52f | ||
|
|
65881829c5 | ||
|
|
99f946f33a | ||
|
|
8051bf7a63 | ||
|
|
9863d82e97 | ||
|
|
a56fef71fb | ||
|
|
db24520d75 | ||
|
|
ca23b4e4d4 | ||
|
|
9e9952eb53 | ||
|
|
90d63e19dd | ||
|
|
fe91a737d5 | ||
|
|
419f5c9968 | ||
|
|
809e361760 | ||
|
|
f5cc10c7df | ||
|
|
c225388951 | ||
|
|
6d50e32d27 | ||
|
|
6711223ad1 | ||
|
|
4e04972a09 | ||
|
|
a22b53a356 | ||
|
|
5e5aefd745 |
No files matched your search
@@ -2,9 +2,16 @@
|
||||
|
||||
name: Continuous Integration expired token tests
|
||||
|
||||
env:
|
||||
NODE_VERSION: 26
|
||||
JAVA_VERSION: 25
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 8 * * *'
|
||||
push:
|
||||
paths-ignore:
|
||||
- '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
|
||||
@@ -34,16 +41,16 @@ jobs:
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ vars.NODE_VERSION }}
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ vars.JAVA_VERSION }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
|
||||
- name: Print Versions
|
||||
run: |
|
||||
@@ -53,7 +60,7 @@ jobs:
|
||||
node --version
|
||||
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
@@ -61,7 +68,7 @@ jobs:
|
||||
${{ runner.os }}-maven-
|
||||
|
||||
- name: Cache npm
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -79,7 +86,7 @@ jobs:
|
||||
# cd ..
|
||||
|
||||
- name: Checkout specific branch fo skills-service
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: NationalSecurityAgency/skills-service
|
||||
path: skills-service
|
||||
@@ -134,7 +141,7 @@ jobs:
|
||||
|
||||
- name: upload result artifacts
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: result artifacts
|
||||
path: |
|
||||
|
||||
@@ -2,17 +2,16 @@
|
||||
|
||||
name: Continuous Integration with OAuth
|
||||
|
||||
env:
|
||||
NODE_VERSION: 26
|
||||
JAVA_VERSION: 25
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
- .github/workflows/skills-service-backward-compat.yml
|
||||
- .github/workflows/client-libs-backward-compat.yml
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '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
|
||||
@@ -43,16 +42,16 @@ jobs:
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ vars.NODE_VERSION }}
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ vars.JAVA_VERSION }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
|
||||
- name: Print Versions
|
||||
run: |
|
||||
@@ -62,7 +61,7 @@ jobs:
|
||||
node --version
|
||||
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
@@ -70,7 +69,7 @@ jobs:
|
||||
${{ runner.os }}-maven-
|
||||
|
||||
- name: Cache npm
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -86,7 +85,7 @@ jobs:
|
||||
# cd ..
|
||||
|
||||
- name: Checkout specific branch fo skills-service
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: NationalSecurityAgency/skills-service
|
||||
path: skills-service
|
||||
@@ -165,7 +164,7 @@ jobs:
|
||||
|
||||
- name: upload result artifacts
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: result artifacts
|
||||
path: |
|
||||
|
||||
@@ -2,17 +2,16 @@
|
||||
|
||||
name: Continuous Integration
|
||||
|
||||
env:
|
||||
NODE_VERSION: 26
|
||||
JAVA_VERSION: 25
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
- .github/workflows/skills-service-backward-compat.yml
|
||||
- .github/workflows/client-libs-backward-compat.yml
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '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
|
||||
@@ -43,16 +42,16 @@ jobs:
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ vars.NODE_VERSION }}
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ vars.JAVA_VERSION }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
|
||||
- name: Print Versions
|
||||
run: |
|
||||
@@ -62,7 +61,7 @@ jobs:
|
||||
node --version
|
||||
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
@@ -71,7 +70,7 @@ jobs:
|
||||
|
||||
|
||||
- name: Checkout specific branch fo skills-service
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: NationalSecurityAgency/skills-service
|
||||
path: skills-service
|
||||
@@ -112,7 +111,7 @@ jobs:
|
||||
|
||||
- name: upload result artifacts
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: result artifacts
|
||||
path: |
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
name: Client Libs Backward Compatibility
|
||||
|
||||
env:
|
||||
NODE_VERSION: 26
|
||||
JAVA_VERSION: 25
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
- .github/workflows/skills-service-backward-compat.yml
|
||||
- .github/workflows/client-libs-backward-compat.yml
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
- .github/workflows/skills-service-backward-compat.yml
|
||||
- .github/workflows/client-libs-backward-compat.yml
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -37,16 +36,16 @@ jobs:
|
||||
build_skills_client_int:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ vars.NODE_VERSION }}
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ vars.JAVA_VERSION }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
|
||||
- name: Print Versions
|
||||
run: |
|
||||
@@ -56,7 +55,7 @@ jobs:
|
||||
node --version
|
||||
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
@@ -64,7 +63,7 @@ jobs:
|
||||
${{ runner.os }}-maven-
|
||||
|
||||
- name: Cache npm
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -83,7 +82,7 @@ jobs:
|
||||
cd ../
|
||||
|
||||
- name: upload service jar
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: service jar
|
||||
path: ./skills-client-integration/skills-int-service/target/skills-int-service-*.jar
|
||||
@@ -117,16 +116,16 @@ jobs:
|
||||
matrix:
|
||||
version: ${{ fromJSON(needs.get_skills_service_versions.outputs.versions) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ vars.NODE_VERSION }}
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ vars.JAVA_VERSION }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
|
||||
- name: Print Versions
|
||||
run: |
|
||||
@@ -136,7 +135,7 @@ jobs:
|
||||
node --version
|
||||
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
@@ -144,7 +143,7 @@ jobs:
|
||||
${{ runner.os }}-maven-
|
||||
|
||||
- name: Cache npm
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -160,7 +159,7 @@ jobs:
|
||||
cd ..
|
||||
|
||||
- name: download integration test apps
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: service jar
|
||||
path: ./skills-client-integration/skills-int-service/target/
|
||||
@@ -182,7 +181,7 @@ jobs:
|
||||
|
||||
- name: upload result artifacts
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: result artifacts for ${{ matrix.version }}
|
||||
path: |
|
||||
|
||||
@@ -17,14 +17,6 @@ set -e
|
||||
set -o pipefail
|
||||
|
||||
echo "------- START: Setup npm links -------"
|
||||
#cd skills-client-integration/skills-int-e2e-test
|
||||
#mvn --batch-mode clean package -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
|
||||
#ls -la target/skills-int-e2e-test-*.jar
|
||||
#du -sh target/*
|
||||
#java --version
|
||||
#java -cp target/skills-int-e2e-test-*.jar -Dloader.main=skills.SetupNpmLinks org.springframework.boot.loader.launch.PropertiesLauncher
|
||||
#cd ../../
|
||||
|
||||
cd skills-client-js
|
||||
echo "------- skills-client-js: npm link -------"
|
||||
npm link
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
name: Skills-service Backward Compatibility
|
||||
|
||||
env:
|
||||
NODE_VERSION: 26
|
||||
JAVA_VERSION: 25
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -10,8 +13,6 @@ on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
schedule:
|
||||
- cron: '0 6 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
@@ -21,18 +22,18 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ vars.NODE_VERSION }}
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: |
|
||||
11
|
||||
${{ vars.JAVA_VERSION }}
|
||||
${{ env.JAVA_VERSION }}
|
||||
|
||||
- name: Print Versions
|
||||
run: |
|
||||
@@ -42,7 +43,7 @@ jobs:
|
||||
node --version
|
||||
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
@@ -50,7 +51,7 @@ jobs:
|
||||
${{ runner.os }}-maven-
|
||||
|
||||
- name: Cache npm
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -58,7 +59,7 @@ jobs:
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Checkout specific branch fo skills-service
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: NationalSecurityAgency/skills-service
|
||||
path: skills-service
|
||||
@@ -70,7 +71,7 @@ jobs:
|
||||
cd ..
|
||||
|
||||
- name: upload service jar
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: service jar
|
||||
path: ./skills-service/service/target/skills-service-*.jar
|
||||
@@ -82,7 +83,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
skillsJsVersion: [ '3.1.1', '3.2.0', '3.3.0', '3.3.1', '3.4.0', '3.4.1', '3.5.0']
|
||||
skillsJsVersion: [ '3.5.0', '3.6.0', '3.6.1', '3.6.2', '3.6.3']
|
||||
|
||||
services:
|
||||
postgres:
|
||||
@@ -105,18 +106,18 @@ jobs:
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ vars.NODE_VERSION }}
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: |
|
||||
11
|
||||
${{ vars.JAVA_VERSION }}
|
||||
${{ env.JAVA_VERSION }}
|
||||
|
||||
- name: Print Versions
|
||||
run: |
|
||||
@@ -126,7 +127,7 @@ jobs:
|
||||
node --version
|
||||
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
@@ -134,7 +135,7 @@ jobs:
|
||||
${{ runner.os }}-maven-
|
||||
|
||||
- name: Cache npm
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -152,7 +153,7 @@ jobs:
|
||||
# cd ..
|
||||
|
||||
# - name: Checkout specific branch fo skills-service
|
||||
# uses: actions/checkout@v4
|
||||
# uses: actions/checkout@v6
|
||||
# with:
|
||||
# repository: NationalSecurityAgency/skills-service
|
||||
# path: skills-service
|
||||
@@ -165,7 +166,7 @@ jobs:
|
||||
# ls ./
|
||||
# cd ..
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: service jar
|
||||
path: ./skills-service/
|
||||
@@ -203,7 +204,7 @@ jobs:
|
||||
|
||||
- name: upload result artifacts
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: result artifacts for [${{ matrix.skillsJsVersion }}] version
|
||||
path: |
|
||||
@@ -229,7 +230,7 @@ jobs:
|
||||
#
|
||||
# - name: upload result artifacts
|
||||
# if: ${{ always() }}
|
||||
# uses: actions/upload-artifact@v4
|
||||
# uses: actions/upload-artifact@v7
|
||||
# with:
|
||||
# name: result artifacts
|
||||
# path: |
|
||||
|
||||
@@ -16,3 +16,5 @@
|
||||
/skills-client-ng/dist/
|
||||
/skills-client-ng/projects/skilltree/skills-client-ng/src/version.js
|
||||
/skills-client-integration/skills-int-e2e-test/cypress/downloads/*
|
||||
|
||||
AGENTS.md
|
||||
@@ -1,10 +1,16 @@
|
||||
# SkillTree Client Libraries
|
||||
<p>
|
||||
<img src="https://img.shields.io/npm/d18m/%40skilltree%2Fskills-client-js" alt="npm downloads">
|
||||
<img src="https://img.shields.io/npm/dw/%40skilltree%2Fskills-client-js" alt="npm weekly downloads">
|
||||
<img src="https://img.shields.io/npm/l/%40skilltree%2Fskills-client-js" alt="License">
|
||||
<img src="https://img.shields.io/npm/v/%40skilltree%2Fskills-client-js" alt="Latest Version">
|
||||
<img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/%40skilltree%2Fskills-client-js">
|
||||
</p>
|
||||
|
||||
SkillTree is an innovative approach to implementing application training. SkillTree skills-client project is an assembly of
|
||||
client libraries that facilitate rapid integration with the SkillTree service.
|
||||
SkillTree is an innovative approach to implementing application training. SkillTree's ``skills-client-js`` project facilitates rapid integration with the SkillTree service.
|
||||
|
||||
To learn about the SkillTree platform please visit our [Official Documentation](https://skilltreeplatform.dev/).
|
||||
These pages provide in-depth guidance on the installation, usage and contribution.
|
||||
To learn about the SkillTree platform please visit our [Official Documentation](https://skilltreeplatform.dev/).
|
||||
These pages provide in-depth guidance on the installation, usage and contribution.
|
||||
|
||||
## Workflow Status
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.5.3</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>3.6.1-SNAPSHOT</version>
|
||||
<version>3.6.5-SNAPSHOT</version>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
@@ -31,10 +31,6 @@
|
||||
<properties>
|
||||
<!--suppress UnresolvedMavenProperty -->
|
||||
<nexusServer>${nexus.url}</nexusServer>
|
||||
<frontend-maven-plugin.version>1.10.3</frontend-maven-plugin.version>
|
||||
|
||||
<!-- TODO: Temporary override spring boot versions, remove once spring boot upgrades these versions -->
|
||||
<commons-lang3.version>3.18.0</commons-lang3.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "skills-int-client-js",
|
||||
"version": "3.6.1",
|
||||
"version": "3.6.5",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib Integration Tests - Native JS",
|
||||
"main": "index.js",
|
||||
@@ -16,13 +16,13 @@
|
||||
},
|
||||
"author": "SkillTree Team",
|
||||
"dependencies": {
|
||||
"@skilltree/skills-client-js": "3.6.1",
|
||||
"axios": "1.10.0",
|
||||
"bootstrap": "5.3.7",
|
||||
"jquery": "3.7.1"
|
||||
"@skilltree/skills-client-js": "3.6.5",
|
||||
"axios": "1.20.0",
|
||||
"bootstrap": "5.3.8",
|
||||
"jquery": "4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"fs-extra": "11.3.0",
|
||||
"fs-extra": "11.4.0",
|
||||
"license-check-and-add": "4.0.5",
|
||||
"license-checker": "25.0.1",
|
||||
"live-server": "1.2.2"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<version>3.6.1-SNAPSHOT</version>
|
||||
<version>3.6.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skills-int-client-js</artifactId>
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ const homePage = '/native/index.html'
|
||||
|
||||
context("Global Events Tests", () => {
|
||||
|
||||
const level1CompleteRegex = /"completed"\s*:\s*\[(?=[\s\S]*?\{[^{}]*?(?:"type"\s*:\s*"Overall"[^{}]*?"level"\s*:\s*1|"level"\s*:\s*1[^{}]*?"type"\s*:\s*"Overall")[^{}]*?\})[\s\S]*?\]/;
|
||||
|
||||
it("global event show correct results", () => {
|
||||
cy.createDefaultProject();
|
||||
|
||||
@@ -34,7 +36,7 @@ context("Global Events Tests", () => {
|
||||
cy.get('pre[data-cy=globalEventResult]').contains('"skillId": "IronMan"')
|
||||
cy.get('pre[data-cy=globalEventResult]').contains('"pointsEarned": 50')
|
||||
cy.get('pre[data-cy=globalEventResult]').contains('"skillApplied": true')
|
||||
cy.get('pre[data-cy=globalEventResult]').contains(/completed": [[][^]*"type": "Overall",[^]\s*"level": 1/)
|
||||
cy.get('pre[data-cy=globalEventResult]').contains(level1CompleteRegex)
|
||||
});
|
||||
it("global event show correct results (skills reported directly to backend endpoint)", () => {
|
||||
cy.createDefaultProject();
|
||||
@@ -46,7 +48,7 @@ context("Global Events Tests", () => {
|
||||
cy.get('pre[data-cy=globalEventResult]').contains('"skillId": "IronMan"')
|
||||
cy.get('pre[data-cy=globalEventResult]').contains('"pointsEarned": 50')
|
||||
cy.get('pre[data-cy=globalEventResult]').contains('"skillApplied": true')
|
||||
cy.get('pre[data-cy=globalEventResult]').contains(/completed": [[][^]*"type": "Overall",[^]\s*"level": 1/)
|
||||
cy.get('pre[data-cy=globalEventResult]').contains(level1CompleteRegex)
|
||||
});
|
||||
|
||||
it('global event does not update when skill reported for a different project', () => {
|
||||
|
||||
@@ -18,6 +18,8 @@ const homePage = '/native/index.html'
|
||||
|
||||
context("Token timeout JS Tests", () => {
|
||||
|
||||
const level1CompleteRegex = /"completed"\s*:\s*\[(?=[\s\S]*?\{[^{}]*?(?:"type"\s*:\s*"Overall"[^{}]*?"level"\s*:\s*1|"level"\s*:\s*1[^{}]*?"type"\s*:\s*"Overall")[^{}]*?\})[\s\S]*?\]/;
|
||||
|
||||
if (Cypress.env('timeout') === true || Cypress.env('timeout') === 'true') {
|
||||
it("report skill with expired token, retry checker will resend with new token", () => {
|
||||
cy.createDefaultProject();
|
||||
@@ -28,14 +30,17 @@ context("Token timeout JS Tests", () => {
|
||||
cy.wait(71000) // wait 71 seconds to ensure the token has expired
|
||||
cy.get('[data-cy="exampleDirectiveClickEventButton"]').click();
|
||||
|
||||
cy.get('pre[data-cy=globalEventResult]').should('be.empty');
|
||||
// should be empty string or empty JSON object
|
||||
cy.get('pre[data-cy=globalEventResult]')
|
||||
.invoke('text')
|
||||
.should('match', /^\s*$|^\s*\{\s*\}\s*$/);
|
||||
|
||||
cy.wait("@getToken", { timeout: 60000 }); // wait ~ another 50 seconds to all for the RetryChecker to resubmit
|
||||
|
||||
cy.get('pre[data-cy=globalEventResult]').contains('"skillId": "IronMan"')
|
||||
cy.get('pre[data-cy=globalEventResult]').contains('"pointsEarned": 50')
|
||||
cy.get('pre[data-cy=globalEventResult]').contains('"skillApplied": true')
|
||||
cy.get('pre[data-cy=globalEventResult]').contains(/completed": [[][^]*"type": "Overall",[^]\s*"level": 1/)
|
||||
cy.get('pre[data-cy=globalEventResult]').contains(level1CompleteRegex)
|
||||
});
|
||||
|
||||
it('skill display - navigate after token expires', () => {
|
||||
|
||||
@@ -45,6 +45,44 @@ const baseUrl = Cypress.config().baseUrl;
|
||||
const skillsDisplayHomePage = '/native/clientDisplay.html'
|
||||
|
||||
|
||||
// cy.request does not add Axios's X-XSRF-TOKEN header automatically. Keep the
|
||||
// cookie and header in sync for requests to the Skills Service, including
|
||||
// registration and login requests made before the browser visits the dashboard.
|
||||
Cypress.Commands.overwrite('request', (originalFn, ...args) => {
|
||||
const options = typeof args[0] === 'object'
|
||||
? { ...args[0] }
|
||||
: typeof args[1] === 'string'
|
||||
? { method: args[0], url: args[1], body: args[2] }
|
||||
: { url: args[0], body: args[1] };
|
||||
const method = (options.method || 'GET').toUpperCase();
|
||||
const url = new URL(options.url, Cypress.config('baseUrl'));
|
||||
const backend = new URL(Cypress.config('baseUrl'));
|
||||
const isSkillsService = url.origin === backend.origin ||
|
||||
(url.hostname === backend.hostname && url.port === '8080');
|
||||
|
||||
if (!isSkillsService || ['GET', 'HEAD', 'OPTIONS', 'TRACE'].includes(method)) {
|
||||
return originalFn(...args);
|
||||
}
|
||||
|
||||
return cy.getCookie('XSRF-TOKEN').then((cookie) => {
|
||||
if (cookie) {
|
||||
return originalFn({
|
||||
...options,
|
||||
headers: { ...options.headers, 'X-XSRF-TOKEN': cookie.value },
|
||||
});
|
||||
}
|
||||
|
||||
// The first request can be registration, logout, or login. A GET loads
|
||||
// the token without requiring an authenticated session.
|
||||
return cy.request({ url: `${url.origin}/app/userInfo` })
|
||||
.then(() => cy.getCookie('XSRF-TOKEN').should('exist'))
|
||||
.then((xsrfCookie) => originalFn({
|
||||
...options,
|
||||
headers: { ...options.headers, 'X-XSRF-TOKEN': xsrfCookie.value },
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('onlyOn', (enabled) => {
|
||||
if (enabled !== true) {
|
||||
cy.state('runnable').ctx.skip()
|
||||
@@ -59,15 +97,20 @@ Cypress.Commands.add("backendRegister", (user, pass, grantRoot) => {
|
||||
return cy.request(`${backend}/app/users/validExistingDashboardUserId/${user}`)
|
||||
.then((response) => {
|
||||
if (response.body !== true) {
|
||||
cy.log(`Creating user [${user}]`)
|
||||
cy.request('PUT', `${backend}/createAccount`, {
|
||||
|
||||
const userBody = {
|
||||
firstName: 'Firstname',
|
||||
lastName: 'LastName',
|
||||
email: user,
|
||||
password: pass,
|
||||
});
|
||||
}
|
||||
|
||||
if (grantRoot) {
|
||||
cy.request('POST', `${backend}/grantFirstRoot`);
|
||||
cy.log(`Creating root user [${user}]`)
|
||||
cy.request('PUT', `${backend}/createRootAccount`, userBody)
|
||||
} else {
|
||||
cy.log(`Creating user [${user}]`)
|
||||
cy.request('PUT', `${backend}/createAccount`, userBody);
|
||||
}
|
||||
cy.backendLogout()
|
||||
} else {
|
||||
@@ -230,18 +273,23 @@ Cypress.Commands.add('skillsLog', (message) => {
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('loginBySingleSignOn', (projId = 'proj1') => {
|
||||
Cypress.Commands.add('loginBySingleSignOn', () => {
|
||||
Cypress.log({
|
||||
name: 'loginBySingleSignOn',
|
||||
})
|
||||
|
||||
// first try to get a skills token,
|
||||
cy.request({
|
||||
url: `http://localhost:8080/api/projects/${projId}/token`,
|
||||
// Check the session without saving a protected request for Spring to replay
|
||||
// after OAuth login, before the test has created any projects.
|
||||
return cy.request({
|
||||
url: `${backend}/app/userInfo`,
|
||||
failOnStatusCode: false,
|
||||
}).then((tokenResp) => {
|
||||
if (tokenResp.status === 401) {
|
||||
cy.skillsLog('Skills token request failed, authenticating with OAuth provider...');
|
||||
followRedirect: false,
|
||||
}).then((sessionResp) => {
|
||||
const requiresLogin = sessionResp.status === 401 ||
|
||||
(sessionResp.status === 200 && !sessionResp.body?.userId) ||
|
||||
([301, 302, 303, 307, 308].includes(sessionResp.status) && Boolean(sessionResp.headers.location));
|
||||
if (requiresLogin) {
|
||||
cy.skillsLog('Skills session requires authentication, authenticating with OAuth provider...');
|
||||
cy.request({
|
||||
url: 'http://localhost:8080/oauth2/authorization/hydra',
|
||||
qs: { skillsRedirectUri: baseUrl, },
|
||||
@@ -253,10 +301,14 @@ Cypress.Commands.add('loginBySingleSignOn', (projId = 'proj1') => {
|
||||
const $html = Cypress.$(resp.body)
|
||||
const authenticityToken = $html.find('input[name=_csrf]').val()
|
||||
const challenge = $html.find('input[name=challenge]').val()
|
||||
expect(authenticityToken, 'OAuth login CSRF token').to.be.a('string').and.not.be.empty;
|
||||
expect(challenge, 'OAuth login challenge').to.be.a('string').and.not.be.empty;
|
||||
const options = {
|
||||
method: 'POST',
|
||||
url: 'http://localhost:3000/login',
|
||||
form: true, // we are submitting a regular form body
|
||||
followRedirect: false,
|
||||
failOnStatusCode: false,
|
||||
body: {
|
||||
_csrf: authenticityToken,
|
||||
challenge,
|
||||
@@ -268,38 +320,53 @@ Cypress.Commands.add('loginBySingleSignOn', (projId = 'proj1') => {
|
||||
};
|
||||
|
||||
cy.request(options).then((resp2) => {
|
||||
expect(resp2.status).to.eq(200)
|
||||
expect(
|
||||
resp2.status,
|
||||
`OAuth login: ${JSON.stringify({
|
||||
location: resp2.headers.location,
|
||||
body: resp2.body,
|
||||
})}`,
|
||||
).to.eq(302);
|
||||
|
||||
if (resp2.redirects[resp2.redirects.length-1].includes('/consent?consent_challenge')) {
|
||||
cy.skillsLog('Granting consent with OAuth provider...');
|
||||
const $html = Cypress.$(resp2.body)
|
||||
const authenticityToken = $html.find('input[name=_csrf]').val()
|
||||
const challenge = $html.find('input[name=challenge]').val()
|
||||
// const consentUrl = resp2.redirects.filter(r => r.includes('/consent?consent_challenge'))[0].split(' ')[1]
|
||||
const options = {
|
||||
method: 'POST',
|
||||
url: 'http://localhost:3000/consent',
|
||||
form: true, // we are submitting a regular form body
|
||||
qs: { consent_challenge: challenge },
|
||||
body: {
|
||||
_csrf: authenticityToken,
|
||||
challenge,
|
||||
grant_scope: 'openid',
|
||||
// grant_scope: 'offline',
|
||||
submit: 'Allow access',
|
||||
remember: '1',
|
||||
},
|
||||
failOnStatusCode: false,
|
||||
};
|
||||
expect(resp2.headers.location, 'OAuth login redirect').to.be.a('string').and.not.be.empty;
|
||||
const redirectUrl = new URL(resp2.headers.location, options.url).href;
|
||||
return cy.request(redirectUrl).then((resp2) => {
|
||||
expect(resp2.status).to.eq(200)
|
||||
|
||||
cy.request(options).then((resp3) => {
|
||||
expect(resp3.status).to.eq(200)
|
||||
})
|
||||
}
|
||||
if ((resp2.redirects || []).some(redirect => redirect.includes('/consent?consent_challenge')) &&
|
||||
Cypress.$(resp2.body).find('input[name=challenge]').length > 0) {
|
||||
cy.skillsLog('Granting consent with OAuth provider...');
|
||||
const $html = Cypress.$(resp2.body)
|
||||
const authenticityToken = $html.find('input[name=_csrf]').val()
|
||||
const challenge = $html.find('input[name=challenge]').val()
|
||||
const options = {
|
||||
method: 'POST',
|
||||
url: 'http://localhost:3000/consent',
|
||||
form: true, // we are submitting a regular form body
|
||||
qs: { consent_challenge: challenge },
|
||||
body: {
|
||||
_csrf: authenticityToken,
|
||||
challenge,
|
||||
grant_scope: 'openid',
|
||||
submit: 'Allow access',
|
||||
remember: '1',
|
||||
},
|
||||
failOnStatusCode: false,
|
||||
};
|
||||
|
||||
cy.request(options).then((resp3) => {
|
||||
expect(resp3.status).to.eq(200)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
} else {
|
||||
cy.skillsLog('Received Skills token, already authenticated with OAuth provider.');
|
||||
expect(sessionResp.status, 'Skills session response status').to.eq(200)
|
||||
cy.skillsLog('Skills session already authenticated with OAuth provider.');
|
||||
}
|
||||
})
|
||||
});
|
||||
}).then(() => cy.request(`${backend}/app/userInfo`).then((resp) => {
|
||||
expect(resp.status, 'Authenticated Skills session status').to.eq(200)
|
||||
expect(resp.body.userId, 'Authenticated Skills user').to.be.a('string').and.not.be.empty;
|
||||
}))
|
||||
});
|
||||
@@ -52,8 +52,8 @@
|
||||
"license-check-and-add": "4.0.5",
|
||||
"license-checker": "25.0.1",
|
||||
"pdf-parse": "1.1.1",
|
||||
"semver": "7.7.2",
|
||||
"wait-on": "8.0.3",
|
||||
"semver": "7.8.5",
|
||||
"wait-on": "9.1.0",
|
||||
"wait-port": "1.1.0"
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<version>3.6.1-SNAPSHOT</version>
|
||||
<version>3.6.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skills-int-e2e-test</artifactId>
|
||||
<description>End to End tests for Skills client libs using skills-int-service app</description>
|
||||
@@ -104,7 +104,6 @@
|
||||
<!-- mvn license:add-third-party-->
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-cli</id>
|
||||
@@ -133,6 +132,7 @@
|
||||
<includedLicense>Common Development and Distribution License 1.1 (CDDL-1.1) + The GNU General Public License (GPL) Version 2 with the Classpath Exception</includedLicense>
|
||||
<includedLicense>Eclipse Public License - Version 2.0</includedLicense>
|
||||
<includedLicense>The GNU General Public License (GPL) Version 2 with the Classpath Exception</includedLicense>
|
||||
<includedLicense>GNU Lesser General Public License</includedLicense>
|
||||
</includedLicenses>
|
||||
<licenseMerges>
|
||||
<licenseMerge>The Apache Software License, Version 2.0|Apache License, Version 2.0</licenseMerge>
|
||||
@@ -145,7 +145,8 @@
|
||||
<licenseMerge>Eclipse Public License - Version 1.0|Eclipse Public License - v 1.0</licenseMerge>
|
||||
<licenseMerge>MIT License|The MIT License</licenseMerge>
|
||||
<licenseMerge>MIT License|MIT</licenseMerge>
|
||||
<licenseMerge>Eclipse Public License - Version 2.0|EPL 2.0</licenseMerge>
|
||||
<licenseMerge>Eclipse Public License - Version 2.0|EPL 2.0|EPL-2.0</licenseMerge>
|
||||
<licenseMerge>Eclipse Public License - Version 2.0|Eclipse Public License - v 2.0</licenseMerge>
|
||||
<licenseMerge>The GNU General Public License (GPL) Version 2 with the Classpath Exception|GPL2 w/ CPE</licenseMerge>
|
||||
</licenseMerges>
|
||||
</configuration>
|
||||
|
||||
+2
-1
@@ -14,7 +14,6 @@
|
||||
spring.datasource.username = postgres
|
||||
spring.datasource.url = jdbc:postgresql://localhost:5432/skills
|
||||
spring.datasource.password = skillsPassword
|
||||
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
|
||||
|
||||
skills.config.ui.userCommunityUserTagKey=dragons
|
||||
skills.config.ui.userCommunityUserTagValue=DivineDragon
|
||||
@@ -38,3 +37,5 @@ logging.level.skills=DEBUG
|
||||
|
||||
skills.config.client.loggingEnabled=true
|
||||
skills.config.client.loggingLevel=TRACE
|
||||
|
||||
skills.config.client.loggingMaxRequestsPerMinute=5000
|
||||
+3
-1
@@ -26,4 +26,6 @@ skills.config.ui.userCommunityParagraphValidationMessage=May not contain divined
|
||||
skills.config.ui.userCommunityRestrictedDescriptor=Divine Dragon
|
||||
skills.config.ui.userCommunityBeforeLabel=For
|
||||
skills.config.ui.userCommunityAfterLabel=Nation
|
||||
skills.config.ui.defaultCommunityDescriptor=All Dragons
|
||||
skills.config.ui.defaultCommunityDescriptor=All Dragons
|
||||
|
||||
skills.config.client.loggingMaxRequestsPerMinute=5000
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>skills</groupId>
|
||||
<artifactId>skills-client-integration</artifactId>
|
||||
<version>3.6.1-SNAPSHOT</version>
|
||||
<version>3.6.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skills-int-service</artifactId>
|
||||
<description>SkillTree Client Lib Integration Tests</description>
|
||||
@@ -23,6 +23,10 @@
|
||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||
<artifactId>httpclient5</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-restclient</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@@ -57,7 +61,6 @@
|
||||
<!-- mvn license:add-third-party-->
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-cli</id>
|
||||
@@ -99,7 +102,8 @@
|
||||
<licenseMerge>Eclipse Public License - Version 1.0|Eclipse Public License 1.0</licenseMerge>
|
||||
<licenseMerge>The 3-Clause BSD License|New BSD License</licenseMerge>
|
||||
<licenseMerge>Eclipse Public License - Version 1.0|Eclipse Public License - v 1.0</licenseMerge>
|
||||
<licenseMerge>Eclipse Public License - Version 2.0|EPL 2.0</licenseMerge>
|
||||
<licenseMerge>Eclipse Public License - Version 2.0|EPL 2.0|EPL-2.0</licenseMerge>
|
||||
<licenseMerge>Eclipse Public License - Version 2.0|Eclipse Public License - v 2.0</licenseMerge>
|
||||
<licenseMerge>The GNU General Public License (GPL) Version 2 with the Classpath Exception|GPL2 w/ CPE</licenseMerge>
|
||||
<licenseMerge>MIT License|MIT</licenseMerge>
|
||||
</licenseMerges>
|
||||
@@ -113,7 +117,6 @@
|
||||
mvn com.mycila:license-maven-plugin:3.0:format-->
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<header>${basedir}/../license-add/LICENSE-HEADER.txt</header>
|
||||
<excludes>
|
||||
|
||||
+7
-4
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -15,10 +15,8 @@
|
||||
*/
|
||||
package skills.example;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.boot.restclient.RestTemplateBuilder;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
@@ -27,6 +25,8 @@ import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import skills.example.SkillsExampleApplication.SkillsConfig;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -128,6 +128,9 @@ public class Controller {
|
||||
|
||||
private void authIfNecessary() {
|
||||
if (!skillsConfig.getAuthMode().equalsIgnoreCase("pki")) {
|
||||
// Seed the session and XSRF-TOKEN before /performLogin, which requires CSRF validation.
|
||||
// SecurityRestTemplateCustomizer retains the cookies and sends X-XSRF-TOKEN on later requests.
|
||||
restTemplate.getForEntity(skillsConfig.getServiceUrl() + "/app/userInfo", String.class);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
+17
-6
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -16,6 +16,8 @@
|
||||
package skills.example;
|
||||
|
||||
import org.apache.hc.client5.http.classic.HttpClient;
|
||||
import org.apache.hc.client5.http.cookie.BasicCookieStore;
|
||||
import org.apache.hc.client5.http.cookie.Cookie;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||
@@ -23,11 +25,9 @@ import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
|
||||
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.hc.core5.http.config.RegistryBuilder;
|
||||
import org.apache.hc.core5.ssl.SSLContextBuilder;
|
||||
import org.apache.hc.core5.ssl.SSLContexts;
|
||||
import org.apache.hc.core5.ssl.TrustStrategy;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.client.RestTemplateCustomizer;
|
||||
import org.springframework.boot.restclient.RestTemplateCustomizer;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
@@ -47,12 +47,22 @@ public class SecurityRestTemplateCustomizer implements RestTemplateCustomizer {
|
||||
// not by default keeps track of session. This method is called by the
|
||||
// RestTemplateBuilder used in the skills.example.Controller constructor
|
||||
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
|
||||
HttpClient client = getHttpClient();
|
||||
BasicCookieStore cookieStore = new BasicCookieStore();
|
||||
HttpClient client = getHttpClient(cookieStore);
|
||||
clientHttpRequestFactory.setHttpClient(client);
|
||||
restTemplate.setRequestFactory(clientHttpRequestFactory);
|
||||
restTemplate.getInterceptors().add((request, body, execution) -> {
|
||||
for (Cookie cookie : cookieStore.getCookies()) {
|
||||
if ("XSRF-TOKEN".equals(cookie.getName())) {
|
||||
request.getHeaders().set("X-XSRF-TOKEN", cookie.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return execution.execute(request, body);
|
||||
});
|
||||
}
|
||||
|
||||
private HttpClient getHttpClient() {
|
||||
private HttpClient getHttpClient(BasicCookieStore cookieStore) {
|
||||
try {
|
||||
SSLContext sslContext = SSLContexts.createSystemDefault();
|
||||
HostnameVerifier allowAllHosts = new NoopHostnameVerifier();
|
||||
@@ -69,6 +79,7 @@ public class SecurityRestTemplateCustomizer implements RestTemplateCustomizer {
|
||||
|
||||
return HttpClients.custom()
|
||||
.useSystemProperties()
|
||||
.setDefaultCookieStore(cookieStore)
|
||||
.setConnectionManager(poolingHttpClientConnectionManager)
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
+6
-3
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -18,15 +18,18 @@ package skills.example.filters;
|
||||
import jakarta.servlet.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
@Order(SecurityProperties.DEFAULT_FILTER_ORDER-1)
|
||||
@Order(VueEntryPointFilter.BEFORE_SECURITY_FILTER_ORDER)
|
||||
public class VueEntryPointFilter implements Filter {
|
||||
|
||||
// -100 (Default Security Order) - 1
|
||||
public static final int BEFORE_SECURITY_FILTER_ORDER = -101;
|
||||
|
||||
@Autowired
|
||||
private VueEntryPointFilterUtils vueEntryPointFilterUtils;
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
module.exports = {
|
||||
"parser": "@babel/eslint-parser",
|
||||
"rules": {
|
||||
"no-underscore-dangle": 0,
|
||||
"max-len": ["error", {'code': 200}],
|
||||
},
|
||||
"globals": {
|
||||
"XMLHttpRequest": 'readonly',
|
||||
"document": 'readonly',
|
||||
"alert": 'readonly',
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"jasmine": true,
|
||||
"jest": true,
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
<!---
|
||||
Copyright 2025 SkillTree
|
||||
Copyright 2026 SkillTree
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -17,15 +17,11 @@ limitations under the License.
|
||||
# SkillTree Client Lib - Native JS Lib
|
||||
|
||||
<p>
|
||||
<a href="https://www.npmjs.com/package/@skilltree/skills-client-js">
|
||||
<img src="https://flat.badgen.net/npm/dt/@skilltree/skills-client-js" alt="npm downloads">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/@skilltree/skills-client-js">
|
||||
<img src="https://flat.badgen.net/npm/dw/@skilltree/skills-client-js" alt="npm weekly downloads">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/@skilltree/skills-client-js">
|
||||
<img src="https://img.shields.io/npm/l/@skilltree/skills-client-js.svg?sanitize=true" alt="License">
|
||||
</a>
|
||||
<img src="https://img.shields.io/npm/d18m/%40skilltree%2Fskills-client-js" alt="npm downloads">
|
||||
<img src="https://img.shields.io/npm/dw/%40skilltree%2Fskills-client-js" alt="npm weekly downloads">
|
||||
<img src="https://img.shields.io/npm/l/%40skilltree%2Fskills-client-js" alt="License">
|
||||
<img src="https://img.shields.io/npm/v/%40skilltree%2Fskills-client-js" alt="Latest Version">
|
||||
<img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/%40skilltree%2Fskills-client-js">
|
||||
</p>
|
||||
|
||||
SkillTree is an innovative approach to implementing application training. SkillTree's ``skills-client-js`` project facilitates rapid integration with the SkillTree service.
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright 2026 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 globals from "globals";
|
||||
import { defineConfig } from "eslint/config";
|
||||
import js from "@eslint/js";
|
||||
|
||||
export default defineConfig([
|
||||
{ files: ["**/*.js"], languageOptions: { globals: globals.browser } },
|
||||
{ files: ["**/*.js"], plugins: { js }, extends: ["js/recommended"] },
|
||||
]);
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright 2025 SkillTree
|
||||
Copyright 2026 SkillTree
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@skilltree/skills-client-js",
|
||||
"version": "3.6.1",
|
||||
"version": "3.6.5",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SkillTree Client Lib - Native JS Lib",
|
||||
"main": "dist/skills-client-js.umd.min.js",
|
||||
@@ -17,46 +17,46 @@
|
||||
"licenseHeaderCheck": " npx license-check-and-add check -f license-add/license-add-config.json",
|
||||
"licenseHeaderAdd": " npx license-check-and-add add -f license-add/license-add-config.json",
|
||||
"licenseCheck": "npm run licenseHeaderCheck && npm run licenseDepCheck ",
|
||||
"build": "npm run licenseCheck && npm run test && npm run clean && npm run build:umd && npm run build:esm",
|
||||
"buildSkipTests": "npm run clean && npm run build:umd && npm run build:esm",
|
||||
"build": "npm run lint && npm run licenseCheck && npm run test && npm run clean && npm run build:umd && npm run build:esm",
|
||||
"buildSkipTests": "npm run lint && npm run clean && npm run build:umd && npm run build:esm",
|
||||
"build:umd": "rollup --config --format umd --file dist/skills-client-js.umd.min.js --name SkillsClient --bundleConfigAsCjs",
|
||||
"build:esm": "rollup --config --format esm --file dist/skills-client-js.esm.min.js --bundleConfigAsCjs",
|
||||
"deploy-to-examples": "npm run build && cp ./dist/skills-display-js.umd.min.js ../skills-examples/skills-example-client-js/app/assets/js/@skilltree/skills-client-js/dist",
|
||||
"deploy-to-examples": "npm run clean && npm run build:umd && npm run build:esm && rm ../skills-client-integration/skills-int-service/src/main/resources/public/native/assets/js/@skilltree/skills-client-js/dist/* && cp ./dist/* ../skills-client-integration/skills-int-service/src/main/resources/public/native/assets/js/@skilltree/skills-client-js/dist/",
|
||||
"test": "NODE_ENV=test jest --coverage",
|
||||
"test-watch": "npx jest --passWithNoTests --coverage --watch",
|
||||
"prepublishOnly": "npm run build",
|
||||
"lint": "eslint --ext .js src/**"
|
||||
"lint": "eslint src/**"
|
||||
},
|
||||
"author": "SkillTree Team",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.28.0",
|
||||
"@babel/core": "7.28.0",
|
||||
"@babel/eslint-parser": "7.28.0",
|
||||
"@babel/plugin-transform-runtime": "7.28.0",
|
||||
"@babel/cli": "7.28.6",
|
||||
"@babel/core": "7.29.6",
|
||||
"@babel/plugin-transform-runtime": "7.29.0",
|
||||
"@babel/polyfill": "7.12.1",
|
||||
"@babel/preset-env": "7.28.0",
|
||||
"@babel/runtime": "7.27.6",
|
||||
"@rollup/plugin-babel": "6.0.4",
|
||||
"@rollup/plugin-commonjs": "28.0.6",
|
||||
"@rollup/plugin-eslint": "9.0.5",
|
||||
"@babel/preset-env": "7.29.5",
|
||||
"@babel/runtime": "7.29.2",
|
||||
"@eslint/js": "10.0.1",
|
||||
"@rollup/plugin-babel": "7.1.0",
|
||||
"@rollup/plugin-commonjs": "29.0.3",
|
||||
"@rollup/plugin-json": "6.1.0",
|
||||
"@rollup/plugin-node-resolve": "16.0.1",
|
||||
"@rollup/plugin-replace": "6.0.2",
|
||||
"@rollup/plugin-terser": "0.4.4",
|
||||
"@rollup/plugin-node-resolve": "16.0.3",
|
||||
"@rollup/plugin-replace": "6.0.3",
|
||||
"@rollup/plugin-terser": "1.0.0",
|
||||
"axios-mock-adapter": "2.1.0",
|
||||
"babel-jest": "30.0.4",
|
||||
"eslint": "9.31.0",
|
||||
"jest": "30.0.4",
|
||||
"jest-environment-jsdom": "29.7.0",
|
||||
"babel-jest": "30.5.1",
|
||||
"eslint": "10.10.0",
|
||||
"globals": "17.12.0",
|
||||
"jest": "30.5.1",
|
||||
"jest-environment-jsdom": "30.5.1",
|
||||
"license-check-and-add": "4.0.5",
|
||||
"license-checker": "25.0.1",
|
||||
"regenerator-runtime": "0.14.1",
|
||||
"rollup": "4.45.1",
|
||||
"rollup": "4.63.3",
|
||||
"xhr-mock": "2.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@stomp/stompjs": "7.1.1",
|
||||
"axios": "1.10.0",
|
||||
"@stomp/stompjs": "7.3.0",
|
||||
"axios": "1.20.0",
|
||||
"js-logger": "1.6.1",
|
||||
"postmate": "1.5.2",
|
||||
"sockjs-client": "1.6.1"
|
||||
@@ -76,4 +76,4 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/NationalSecurityAgency/skills-client/issues"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2025 SkillTree
|
||||
Copyright 2026 SkillTree
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -13,7 +13,6 @@ 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 eslint from '@rollup/plugin-eslint';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
@@ -34,7 +33,6 @@ module.exports = {
|
||||
},
|
||||
preserveSymlinks: true,
|
||||
plugins: [
|
||||
eslint(),
|
||||
babel({
|
||||
babelHelpers: 'runtime',
|
||||
exclude: 'node_modules/**',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -58,7 +58,7 @@ export default {
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', `${conf.getServiceUrl()}/api/projects/${conf.getProjectId()}/skillsClientVersion`);
|
||||
xhr.withCredentials = true;
|
||||
xhr.withCredentials = conf.isPKIMode();
|
||||
if (!conf.isPKIMode()) {
|
||||
xhr.setRequestHeader('Authorization', `Bearer ${conf.getAuthToken()}`);
|
||||
}
|
||||
@@ -99,6 +99,10 @@ export default {
|
||||
return typeof authenticator === 'string' && authenticator.startsWith(`${serviceUrl}/oauth2/authorization`);
|
||||
},
|
||||
|
||||
assignWindowLocation(newLocation) {
|
||||
window.location.assign(newLocation);
|
||||
},
|
||||
|
||||
getAuthenticationToken(authenticator, serviceUrl, projectId, oauthRedirect = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const isOAuthMode = this.isOAuthMode(authenticator, serviceUrl);
|
||||
@@ -107,7 +111,6 @@ export default {
|
||||
xhr.open('GET', authenticator);
|
||||
} else {
|
||||
xhr.open('GET', `${serviceUrl}/api/projects/${projectId}/token`);
|
||||
xhr.withCredentials = true;
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = () => {
|
||||
@@ -115,9 +118,9 @@ export default {
|
||||
if (xhr.status !== 200) {
|
||||
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}`;
|
||||
const oauthAuthenticator = `${authenticator}?skillsRedirectUri=${encodeURIComponent(window.location.href)}`;
|
||||
log.info(`SkillsClient::SkillService::unable to get oAuth token, navigating to [${oauthAuthenticator}]`);
|
||||
window.location.assign(oauthAuthenticator);
|
||||
this.assignWindowLocation(oauthAuthenticator);
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(`SkillTree: Unable to authenticate using [${authenticator}] endpoint. Response Code=[${xhr.status}].\n
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -125,7 +125,6 @@ const exportObject = {
|
||||
setConfigureWasCalled();
|
||||
}
|
||||
}).catch((error) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Error getting service status', error);
|
||||
setConfigureWasCalled();
|
||||
initializedResolvers.resolve();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,17 +26,15 @@ const skillsClientDisplayPath = 'skillsClientDisplayPath';
|
||||
const markedForDestruction = [];
|
||||
|
||||
export default class SkillsDisplayJS {
|
||||
/* eslint-disable object-curly-newline */
|
||||
constructor({ options, theme, version, handleRouteChanged, userId } = {}) {
|
||||
log.debug(`SkillsClient::SkillsDisplayJS::Constructing with options [${options}], theme [${theme}], version [${version}], userId [${userId}]`);
|
||||
this._options = { ...{ }, ...options };
|
||||
this._options = { parentPath: window.location.pathname, ...options };
|
||||
this._theme = theme;
|
||||
this._version = version;
|
||||
this._handleRouteChanged = handleRouteChanged;
|
||||
this._userId = userId;
|
||||
}
|
||||
|
||||
/* eslint-disable class-methods-use-this */
|
||||
currentIframeId() {
|
||||
return uniqueId;
|
||||
}
|
||||
@@ -201,7 +199,6 @@ export default class SkillsDisplayJS {
|
||||
errorMessage += ' and that your browser trusts the server\'s certificate';
|
||||
}
|
||||
errorMessage += `. skilltree service URL: ${this.configuration.serviceUrl}`;
|
||||
/* eslint-disable no-console */
|
||||
console.error(errorMessage);
|
||||
log.error(`SkillsClient::SkillsDisplayJS::${errorMessage}`, error);
|
||||
ErrorPageUtils.removeAllChildren(iframeContainer);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,7 +55,7 @@ export default class SkillsLevelJS {
|
||||
this._projectId = SkillsConfiguration.getProjectId();
|
||||
log.debug(`SkillsClient::SkillsLevelJS::getting projectId from SkillsConfiguration: [${this._projectId}]`);
|
||||
}
|
||||
const requestConfig = { withCredentials: true };
|
||||
const requestConfig = { withCredentials: SkillsConfiguration.isPKIMode() };
|
||||
if (!SkillsConfiguration.isPKIMode()) {
|
||||
const authToken = SkillsConfiguration.getAuthToken();
|
||||
requestConfig.headers = { Authorization: `Bearer ${authToken}` };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,7 +32,6 @@ const callSuccessHandlers = (event) => {
|
||||
};
|
||||
|
||||
const callErrorHandlers = (event) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Error reporting skill:', event);
|
||||
errorHandlerCache.forEach((it) => it(event));
|
||||
};
|
||||
@@ -139,7 +138,7 @@ const reportInternal = (resolve, reject, userSkillId, timestamp, isRetry, retryA
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.open('POST', `${SkillsConfiguration.getServiceUrl()}/api/projects/${SkillsConfiguration.getProjectId()}/skills/${userSkillId}`);
|
||||
xhr.withCredentials = true;
|
||||
xhr.withCredentials = SkillsConfiguration.isPKIMode();
|
||||
if (!SkillsConfiguration.isPKIMode()) {
|
||||
xhr.setRequestHeader('Authorization', `Bearer ${SkillsConfiguration.getAuthToken()}`);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
import mock from 'xhr-mock';
|
||||
import SkillsService from '../src/SkillsService';
|
||||
import log from 'js-logger';
|
||||
|
||||
require('@babel/polyfill');
|
||||
|
||||
@@ -22,39 +23,14 @@ describe('OAuth auto redirect tests', () => {
|
||||
const mockServiceUrl = 'http://some.com';
|
||||
const mockProjectId = 'proj1';
|
||||
const authEndpoint = `${mockServiceUrl}/oauth2/authorization/gitlab`;
|
||||
const oldWindowLocation = window.location
|
||||
|
||||
/**
|
||||
* Please note that this test will need to be re-written in order to upgrade
|
||||
* jest-environment-jsdom from 29 to 30; version 30 does not support manipulating
|
||||
* `window.location`, here are some relevant tickets:
|
||||
* https://github.com/jestjs/jest/issues/15674
|
||||
* https://github.com/jsdom/jsdom/issues/3492
|
||||
*/
|
||||
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
|
||||
SkillsService.assignWindowLocation = jest.fn();
|
||||
})
|
||||
|
||||
// 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()
|
||||
SkillsService.assignWindowLocation.mockReset()
|
||||
});
|
||||
|
||||
// put the real XHR object back and clear the mocks after each test
|
||||
@@ -68,8 +44,24 @@ describe('OAuth auto redirect tests', () => {
|
||||
|
||||
await SkillsService.getAuthenticationToken(authEndpoint, mockServiceUrl, mockProjectId, true);
|
||||
|
||||
expect(window.location.assign).toHaveBeenCalledTimes(1)
|
||||
expect(window.location.assign).toHaveBeenCalledWith(`${authEndpoint}?skillsRedirectUri=http://localhost/`)
|
||||
expect(SkillsService.assignWindowLocation).toHaveBeenCalledTimes(1)
|
||||
expect(SkillsService.assignWindowLocation).toHaveBeenCalledWith(`${authEndpoint}?skillsRedirectUri=${encodeURIComponent('http://localhost/')}`)
|
||||
});
|
||||
|
||||
it('oauth redirect encodes the current location so it cannot add query parameters', async () => {
|
||||
const oauthTokenEndpoint = `${mockServiceUrl}/api/projects/${mockProjectId}/token`;
|
||||
mock.get(oauthTokenEndpoint, (req, res) => res.status(401));
|
||||
|
||||
window.history.pushState({}, '', '/page?a=1&skillsRedirectUri=http://evil.example.com/');
|
||||
const injected = window.location.href;
|
||||
|
||||
await SkillsService.getAuthenticationToken(authEndpoint, mockServiceUrl, mockProjectId, true);
|
||||
|
||||
const [redirectedTo] = SkillsService.assignWindowLocation.mock.calls[0];
|
||||
expect(redirectedTo).toBe(`${authEndpoint}?skillsRedirectUri=${encodeURIComponent(injected)}`);
|
||||
// the injected separators must not survive as separators
|
||||
expect(redirectedTo.split('?')).toHaveLength(2);
|
||||
expect(redirectedTo).not.toContain('&skillsRedirectUri=');
|
||||
});
|
||||
|
||||
it('oauth does not auto redirect when oauthRedirect=false', async () => {
|
||||
@@ -80,7 +72,7 @@ describe('OAuth auto redirect tests', () => {
|
||||
await SkillsService.getAuthenticationToken(authEndpoint, mockServiceUrl, mockProjectId);
|
||||
} catch (e) {
|
||||
expect(e.message).toMatch('Unable to authenticate');
|
||||
expect(window.location.assign).toHaveBeenCalledTimes(0);
|
||||
expect(SkillsService.assignWindowLocation).toHaveBeenCalledTimes(0);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -89,8 +81,148 @@ describe('OAuth auto redirect tests', () => {
|
||||
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(SkillsService.assignWindowLocation).toHaveBeenCalledTimes(0);
|
||||
expect(result).toMatch('token1');
|
||||
});
|
||||
|
||||
it('send log message', async () => {
|
||||
const logEndpoint = `${mockServiceUrl}/public/log`;
|
||||
const testMessage = 'Test log message';
|
||||
const testLevel = 'ERROR';
|
||||
|
||||
// Mock the POST request to the log endpoint
|
||||
mock.post(logEndpoint, (req, res) => {
|
||||
// Verify the request body contains expected data
|
||||
expect(req.body()).toContain('message');
|
||||
expect(req.body()).toContain(testMessage);
|
||||
expect(req.body()).toContain(testLevel);
|
||||
return res.status(200).body('{"success": true}');
|
||||
});
|
||||
|
||||
const result = await SkillsService.sendLogMessage(mockServiceUrl, [testMessage], { level: testLevel });
|
||||
|
||||
expect(result).toEqual({ success: true });
|
||||
});
|
||||
|
||||
it('send log message failure', async () => {
|
||||
const logEndpoint = `${mockServiceUrl}/public/log`;
|
||||
const testMessage = 'Test log message';
|
||||
const testLevel = 'ERROR';
|
||||
|
||||
// Mock a failed response
|
||||
mock.post(logEndpoint, (req, res) => res.status(500));
|
||||
|
||||
try {
|
||||
await SkillsService.sendLogMessage(mockServiceUrl, [testMessage], { level: testLevel });
|
||||
fail('Expected sendLogMessage to throw an error');
|
||||
} catch (error) {
|
||||
expect(error.message).toContain('Unable to send client log message');
|
||||
expect(error.message).toContain('Received status [500]');
|
||||
}
|
||||
});
|
||||
|
||||
it('configure logging with enabled logging', async () => {
|
||||
const logEndpoint = `${mockServiceUrl}/public/log`;
|
||||
const testMessage = 'Test log message';
|
||||
|
||||
// Mock the POST request for log message
|
||||
mock.post(logEndpoint, (req, res) => res.status(200).body('{"success": true}'));
|
||||
|
||||
const response = {
|
||||
clientLib: {
|
||||
loggingEnabled: 'true',
|
||||
loggingLevel: 'INFO'
|
||||
}
|
||||
};
|
||||
|
||||
// Mock console.info to capture log output
|
||||
const consoleSpy = jest.spyOn(console, 'info').mockImplementation();
|
||||
|
||||
SkillsService.configureLogging(mockServiceUrl, response);
|
||||
|
||||
// Trigger a log message to test the handler
|
||||
log.info(testMessage);
|
||||
|
||||
// Wait for async log message to be sent
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
|
||||
// Check that our test message was logged
|
||||
expect(consoleSpy.mock.calls.some(call =>
|
||||
call[0] === testMessage || (Array.isArray(call[0]) && call[0].includes(testMessage))
|
||||
)).toBe(true);
|
||||
consoleSpy.mockReset();
|
||||
});
|
||||
|
||||
it('configure logging with unknown level defaults to INFO and logs warning', async () => {
|
||||
const logEndpoint = `${mockServiceUrl}/public/log`;
|
||||
const response = {
|
||||
clientLib: {
|
||||
loggingEnabled: 'true',
|
||||
loggingLevel: 'UNKNOWN_LEVEL'
|
||||
}
|
||||
};
|
||||
|
||||
// Mock the POST request for log message
|
||||
mock.post(logEndpoint, (req, res) => res.status(200).body('{"success": true}'));
|
||||
|
||||
// Spy on the logger's warn method instead of console.warn
|
||||
const logWarnSpy = jest.spyOn(log, 'warn').mockImplementation();
|
||||
const consoleSpy = jest.spyOn(console, 'info').mockImplementation();
|
||||
|
||||
SkillsService.configureLogging(mockServiceUrl, response);
|
||||
|
||||
// Verify the specific warning message was logged
|
||||
expect(logWarnSpy).toHaveBeenCalledWith(
|
||||
'SkillsClient::SkillService::Unknown log level [UNKNOWN_LEVEL], defaulting to INFO'
|
||||
);
|
||||
|
||||
// Verify that logging still works after defaulting to INFO
|
||||
log.info('Test message after defaulting');
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
|
||||
logWarnSpy.mockRestore();
|
||||
consoleSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('reportSkillsClientVersion success', async () => {
|
||||
const mockConfig = {
|
||||
getServiceUrl: () => mockServiceUrl,
|
||||
getProjectId: () => mockProjectId,
|
||||
isPKIMode: () => false,
|
||||
getAuthToken: () => 'test-token'
|
||||
};
|
||||
|
||||
const versionEndpoint = `${mockServiceUrl}/api/projects/${mockProjectId}/skillsClientVersion`;
|
||||
const mockResponse = { success: true, version: '3.6.2' };
|
||||
|
||||
// Mock a successful response (200)
|
||||
mock.post(versionEndpoint, (req, res) => res.status(200).body(JSON.stringify(mockResponse)));
|
||||
|
||||
const result = await SkillsService.reportSkillsClientVersion(mockConfig);
|
||||
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
|
||||
it('reportSkillsClientVersion failure', async () => {
|
||||
const mockConfig = {
|
||||
getServiceUrl: () => mockServiceUrl,
|
||||
getProjectId: () => mockProjectId,
|
||||
isPKIMode: () => false,
|
||||
getAuthToken: () => 'test-token'
|
||||
};
|
||||
|
||||
const versionEndpoint = `${mockServiceUrl}/api/projects/${mockProjectId}/skillsClientVersion`;
|
||||
|
||||
// Mock a failed response (e.g., 401)
|
||||
mock.post(versionEndpoint, (req, res) => res.status(401));
|
||||
|
||||
try {
|
||||
await SkillsService.reportSkillsClientVersion(mockConfig);
|
||||
fail('Expected reportSkillsClientVersion to throw an error');
|
||||
} catch (error) {
|
||||
expect(error.message).toBe('Unable to report skillsClientVersion. Received status [401]');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import mock from 'xhr-mock';
|
||||
import SkillsConfiguration from '../../src/config/SkillsConfiguration';
|
||||
import log from 'js-logger';
|
||||
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
@@ -193,4 +194,32 @@ describe('SkillsConfigurationInit', () => {
|
||||
|
||||
expect(SkillsConfiguration.getServiceUrl()).toBe('http://some');
|
||||
});
|
||||
|
||||
it('configure with enabled=false exercises disabled logging path', () => {
|
||||
// Spy on the logger methods to verify they are called
|
||||
const logUseDefaultsSpy = jest.spyOn(log, 'useDefaults').mockImplementation();
|
||||
const logSetLevelSpy = jest.spyOn(log, 'setLevel').mockImplementation();
|
||||
const logInfoSpy = jest.spyOn(log, 'info').mockImplementation();
|
||||
|
||||
const result = SkillsConfiguration.configure({
|
||||
serviceUrl: 'http://test.com',
|
||||
projectId: 'test-project',
|
||||
authenticator: 'http://test.com/auth',
|
||||
enabled: false
|
||||
});
|
||||
|
||||
// Verify the specific lines are exercised
|
||||
expect(logUseDefaultsSpy).toHaveBeenCalled();
|
||||
expect(logSetLevelSpy).toHaveBeenCalledWith(log.TRACE);
|
||||
expect(logInfoSpy).toHaveBeenCalledWith('SkillsConfiguration is disabled.');
|
||||
|
||||
// Verify it returns a resolved promise
|
||||
expect(result).toBeInstanceOf(Promise);
|
||||
|
||||
// Clean up spies
|
||||
logUseDefaultsSpy.mockRestore();
|
||||
logSetLevelSpy.mockRestore();
|
||||
logInfoSpy.mockRestore();
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -482,6 +482,7 @@ describe('SkillsDisplayJS', () => {
|
||||
isSummaryOnly: false,
|
||||
projectId: mockProjectId,
|
||||
serviceUrl: mockServiceUrl,
|
||||
parentPath: '/',
|
||||
};
|
||||
mockVersion = `${Math.random()}`;
|
||||
|
||||
@@ -497,6 +498,7 @@ describe('SkillsDisplayJS', () => {
|
||||
authenticator: 'pki',
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
parentPath: '/'
|
||||
};
|
||||
|
||||
const client = new SkillsDisplayJS({
|
||||
@@ -538,6 +540,7 @@ describe('SkillsDisplayJS', () => {
|
||||
authenticator: mockAuthenticator,
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
parentPath: '/'
|
||||
};
|
||||
const client = new SkillsDisplayJS({
|
||||
options,
|
||||
@@ -578,6 +581,7 @@ describe('SkillsDisplayJS', () => {
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
internalBackButton: false,
|
||||
parentPath: '/'
|
||||
};
|
||||
const client = new SkillsDisplayJS({
|
||||
options,
|
||||
@@ -618,6 +622,7 @@ describe('SkillsDisplayJS', () => {
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
internalBackButton: true,
|
||||
parentPath: '/'
|
||||
};
|
||||
const client = new SkillsDisplayJS({
|
||||
options,
|
||||
@@ -657,6 +662,7 @@ describe('SkillsDisplayJS', () => {
|
||||
authenticator: mockAuthenticator,
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
parentPath: '/'
|
||||
};
|
||||
const client = new SkillsDisplayJS({
|
||||
options,
|
||||
@@ -695,7 +701,7 @@ describe('SkillsDisplayJS', () => {
|
||||
describe('construction', () => {
|
||||
describe('options', () => {
|
||||
it('accepts options in the constructor', () => {
|
||||
const mockOptions = { authenticator: 'option' };
|
||||
const mockOptions = { authenticator: 'option', parentPath: 'non-default/' };
|
||||
const client = new SkillsDisplayJS({
|
||||
options: mockOptions,
|
||||
});
|
||||
@@ -704,14 +710,14 @@ describe('SkillsDisplayJS', () => {
|
||||
|
||||
it('supports null or undefined being passed', () => {
|
||||
let client = new SkillsDisplayJS({ options: null });
|
||||
expect(client.options).toEqual({});
|
||||
expect(client.options).toEqual({ parentPath: '/' });
|
||||
client = new SkillsDisplayJS({ options: undefined });
|
||||
expect(client.options).toEqual({});
|
||||
expect(client.options).toEqual({ parentPath: '/'} );
|
||||
});
|
||||
|
||||
it('supports empty constructor', () => {
|
||||
it('supports empty constructor, defaults parentPath to window.location.pathname', () => {
|
||||
const client = new SkillsDisplayJS();
|
||||
expect(client.options).toEqual({});
|
||||
expect(client.options).toEqual({ parentPath: '/'} );
|
||||
});
|
||||
|
||||
it('accepts valid options', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,21 +18,33 @@ import mock from 'xhr-mock';
|
||||
import SkillsConfiguration from '../../src/config/SkillsConfiguration';
|
||||
import { SkillsReporter } from '../../src/reporter/SkillsReporter.js';
|
||||
|
||||
// These tests exercise HTTP authentication, not the background websocket connection.
|
||||
jest.mock('@stomp/stompjs');
|
||||
|
||||
describe('authPkiTests()', () => {
|
||||
const mockServiceUrl = 'http://some.com';
|
||||
const mockProjectId = 'proj1';
|
||||
|
||||
SkillsConfiguration.configure({
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
authenticator: 'pki',
|
||||
// replace the real XHR object with the mock XHR object before each test
|
||||
beforeEach(async () => {
|
||||
mock.setup();
|
||||
SkillsConfiguration.logout();
|
||||
mock.get(/.*\/public\/status/, (req, res) => res.status(200).body('{"status":"OK","clientLib":{"loggingEnabled":"false","loggingLevel":"DEBUG"}}'));
|
||||
mock.post(/.*\/api\/projects\/proj1\/skillsClientVersion/, (req, res) => res.status(200).body('{"success":true,"explanation":null}'));
|
||||
await SkillsConfiguration.configure({
|
||||
serviceUrl: mockServiceUrl,
|
||||
projectId: mockProjectId,
|
||||
authenticator: 'pki',
|
||||
});
|
||||
});
|
||||
|
||||
// replace the real XHR object with the mock XHR object before each test
|
||||
beforeEach(() => mock.setup());
|
||||
|
||||
// put the real XHR object back and clear the mocks after each test
|
||||
afterEach(() => mock.teardown());
|
||||
afterEach(() => {
|
||||
SkillsReporter.cancelRetryChecker();
|
||||
window.localStorage.removeItem('skillTreeRetryQueue');
|
||||
SkillsConfiguration.logout();
|
||||
mock.teardown();
|
||||
});
|
||||
|
||||
it('successful call in pki mode', async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 SkillTree
|
||||
* Copyright 2026 SkillTree
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,6 +55,8 @@ describe('userSkillsService', () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
SkillsReporter.cancelRetryChecker();
|
||||
jest.restoreAllMocks();
|
||||
window.XMLHttpRequest = realXMLHttpRequest;
|
||||
});
|
||||
|
||||
@@ -79,9 +81,16 @@ describe('userSkillsService', () => {
|
||||
expect(MockXMLHttpRequest.setRequestHeader).toHaveBeenCalledWith('Authorization', `Bearer ${SkillsConfiguration.getAuthToken()}`);
|
||||
});
|
||||
|
||||
it('enables withCredentials', () => {
|
||||
it('disables withCredentials in token mode', () => {
|
||||
SkillsReporter.reportSkill(mockUserSkillId);
|
||||
expect(MockXMLHttpRequest.withCredentials).toBeTruthy();
|
||||
expect(MockXMLHttpRequest.withCredentials).toBe(false);
|
||||
});
|
||||
|
||||
it('enables withCredentials without an Authorization header in PKI mode', () => {
|
||||
SkillsConfiguration.setAuthToken('pki');
|
||||
SkillsReporter.reportSkill(mockUserSkillId);
|
||||
expect(MockXMLHttpRequest.withCredentials).toBe(true);
|
||||
expect(MockXMLHttpRequest.setRequestHeader).not.toHaveBeenCalledWith('Authorization', expect.anything());
|
||||
});
|
||||
|
||||
it('sends out the ajax request', () => {
|
||||
|
||||
Reference in new issue
Block a user