diff --git a/.gitignore b/.gitignore index 29841ea..f2ccef3 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ pnpm-debug.log* *.sln *.sw? .history -coverage/ \ No newline at end of file +coverage/ +.env \ No newline at end of file diff --git a/example/components/App.vue b/example/components/App.vue index 9b48a66..77bd737 100644 --- a/example/components/App.vue +++ b/example/components/App.vue @@ -2,6 +2,7 @@
Home + Manage Users Login
@@ -21,7 +22,6 @@ const { logout } = useDescope(); font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - text-align: center; color: #2c3e50; } diff --git a/example/components/ManageUsers.vue b/example/components/ManageUsers.vue new file mode 100644 index 0000000..bc5fa69 --- /dev/null +++ b/example/components/ManageUsers.vue @@ -0,0 +1,19 @@ + + + + + + diff --git a/example/router.ts b/example/router.ts index c1a30e3..fb96fc3 100644 --- a/example/router.ts +++ b/example/router.ts @@ -1,6 +1,7 @@ import { createRouter, createWebHistory } from 'vue-router'; import Home from './components/Home.vue'; import Login from './components/Login.vue'; +import ManageUsers from './components/ManageUsers.vue'; import { routeGuard } from '../src'; const router = createRouter({ @@ -32,6 +33,11 @@ const router = createRouter({ path: '/login', name: 'login', component: Login + }, + { + path: '/manage-users', + name: 'manage-users', + component: ManageUsers } ] }); diff --git a/package-lock.json b/package-lock.json index ba4c83c..bdf593c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "2.0.3", "license": "MIT", "dependencies": { + "@descope/user-management-widget": "0.0.7", "@descope/web-component": "3.7.0" }, "devDependencies": { @@ -1800,6 +1801,56 @@ "lodash.get": "4.4.2" } }, + "node_modules/@descope/user-management-widget": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@descope/user-management-widget/-/user-management-widget-0.0.7.tgz", + "integrity": "sha512-VRy6zZwQJduVQDFe3sIJxGLtEasrrdcNBopF38xvQck9eqtqtUK7v1A69YbpKDsW5YmM3dxYrKEs1G+X43j6iA==", + "dependencies": { + "@descope/web-js-sdk": "1.9.4", + "@reduxjs/toolkit": "^2.0.1", + "immer": "^10.0.3", + "redux": "5.0.1", + "redux-thunk": "3.1.0", + "reselect": "5.0.1", + "tslib": "2.6.2" + } + }, + "node_modules/@descope/user-management-widget/node_modules/@descope/core-js-sdk": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@descope/core-js-sdk/-/core-js-sdk-2.9.0.tgz", + "integrity": "sha512-yZZIKRRyvLl/hpdDg1LPgZghfj4klkUyILTERWlBZh9vt8bIBzOqFrqkNcfDfVhxts15dYwlPMykQG8ssQ/Unw==", + "dependencies": { + "jwt-decode": "3.1.2", + "lodash.get": "4.4.2" + } + }, + "node_modules/@descope/user-management-widget/node_modules/@descope/web-js-sdk": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@descope/web-js-sdk/-/web-js-sdk-1.9.4.tgz", + "integrity": "sha512-woYrRJM6thoP0ZwiH6JCmchuo7kuSCCh/dLQVcKmM05hvvg7sVAqv1RM8HnFeLC2Mmyk8+vz92maVZ6WECVFOg==", + "dependencies": { + "@descope/core-js-sdk": "2.9.0", + "@fingerprintjs/fingerprintjs-pro": "3.8.5", + "js-cookie": "3.0.5", + "tslib": "2.6.2" + } + }, + "node_modules/@descope/user-management-widget/node_modules/@fingerprintjs/fingerprintjs-pro": { + "version": "3.8.5", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.8.5.tgz", + "integrity": "sha512-07bkz/BrQYIHh0FIQ8rMKx62IKu+gkZrUzNsoT1fLwYfnM0uk+s+XQXLeaDXGMGpHgkZSP4nPMAn+nkRfWy6ww==", + "dependencies": { + "tslib": "^2.4.1" + } + }, + "node_modules/@descope/user-management-widget/node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "engines": { + "node": ">=14" + } + }, "node_modules/@descope/web-component": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/@descope/web-component/-/web-component-3.7.0.tgz", @@ -2719,6 +2770,29 @@ "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "dev": true }, + "node_modules/@reduxjs/toolkit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.1.0.tgz", + "integrity": "sha512-nfJ/b4ZhzUevQ1ZPKjlDL6CMYxO4o7ZL7OSsvSOxzT/EN11LsBDgTqP7aedHtBrFSVoK7oTP1SbMWUwGb30NLg==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-typescript": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.0.tgz", @@ -9084,6 +9158,15 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz", + "integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz", @@ -15123,6 +15206,19 @@ "node": ">=8.10.0" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmmirror.com/regenerate/-/regenerate-1.4.2.tgz", @@ -15266,6 +15362,11 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, + "node_modules/reselect": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.0.1.tgz", + "integrity": "sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==" + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz", @@ -19534,6 +19635,55 @@ "lodash.get": "4.4.2" } }, + "@descope/user-management-widget": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@descope/user-management-widget/-/user-management-widget-0.0.7.tgz", + "integrity": "sha512-VRy6zZwQJduVQDFe3sIJxGLtEasrrdcNBopF38xvQck9eqtqtUK7v1A69YbpKDsW5YmM3dxYrKEs1G+X43j6iA==", + "requires": { + "@descope/web-js-sdk": "1.9.4", + "@reduxjs/toolkit": "^2.0.1", + "immer": "^10.0.3", + "redux": "5.0.1", + "redux-thunk": "3.1.0", + "reselect": "5.0.1", + "tslib": "2.6.2" + }, + "dependencies": { + "@descope/core-js-sdk": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@descope/core-js-sdk/-/core-js-sdk-2.9.0.tgz", + "integrity": "sha512-yZZIKRRyvLl/hpdDg1LPgZghfj4klkUyILTERWlBZh9vt8bIBzOqFrqkNcfDfVhxts15dYwlPMykQG8ssQ/Unw==", + "requires": { + "jwt-decode": "3.1.2", + "lodash.get": "4.4.2" + } + }, + "@descope/web-js-sdk": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@descope/web-js-sdk/-/web-js-sdk-1.9.4.tgz", + "integrity": "sha512-woYrRJM6thoP0ZwiH6JCmchuo7kuSCCh/dLQVcKmM05hvvg7sVAqv1RM8HnFeLC2Mmyk8+vz92maVZ6WECVFOg==", + "requires": { + "@descope/core-js-sdk": "2.9.0", + "@fingerprintjs/fingerprintjs-pro": "3.8.5", + "js-cookie": "3.0.5", + "tslib": "2.6.2" + } + }, + "@fingerprintjs/fingerprintjs-pro": { + "version": "3.8.5", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.8.5.tgz", + "integrity": "sha512-07bkz/BrQYIHh0FIQ8rMKx62IKu+gkZrUzNsoT1fLwYfnM0uk+s+XQXLeaDXGMGpHgkZSP4nPMAn+nkRfWy6ww==", + "requires": { + "tslib": "^2.4.1" + } + }, + "js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==" + } + } + }, "@descope/web-component": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/@descope/web-component/-/web-component-3.7.0.tgz", @@ -20281,6 +20431,17 @@ "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "dev": true }, + "@reduxjs/toolkit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.1.0.tgz", + "integrity": "sha512-nfJ/b4ZhzUevQ1ZPKjlDL6CMYxO4o7ZL7OSsvSOxzT/EN11LsBDgTqP7aedHtBrFSVoK7oTP1SbMWUwGb30NLg==", + "requires": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" + } + }, "@rollup/plugin-typescript": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.0.tgz", @@ -25345,6 +25506,11 @@ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, + "immer": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz", + "integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz", @@ -29986,6 +30152,17 @@ "picomatch": "^2.2.1" } }, + "redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "requires": {} + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmmirror.com/regenerate/-/regenerate-1.4.2.tgz", @@ -30101,6 +30278,11 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, + "reselect": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.0.1.tgz", + "integrity": "sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==" + }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz", diff --git a/package.json b/package.json index b131a52..6e155f2 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ ] }, "dependencies": { + "@descope/user-management-widget": "0.0.7", "@descope/web-component": "3.7.0" }, "peerDependencies": { diff --git a/src/UserManagement.vue b/src/UserManagement.vue new file mode 100644 index 0000000..b093227 --- /dev/null +++ b/src/UserManagement.vue @@ -0,0 +1,32 @@ + + + + diff --git a/src/index.ts b/src/index.ts index f86c7b5..843d5db 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export { default as Descope } from './Descope.vue'; +export { default as UserManagement } from './UserManagement.vue'; export { useDescope, useSession, useUser } from './hooks'; export { default, routeGuard, getSdk } from './plugin'; export { diff --git a/tests/Descope.test.ts b/tests/Descope.test.ts index fbd22c5..64abc7a 100644 --- a/tests/Descope.test.ts +++ b/tests/Descope.test.ts @@ -1,5 +1,5 @@ import { shallowMount, mount } from '@vue/test-utils'; -import { Descope } from '../src'; +import Descope from '../src/Descope.vue'; jest.mock('../src/hooks', () => ({ useOptions: () => ({ projectId: 'project1', baseUrl: 'baseUrl' }), diff --git a/tests/UserManagement.test.ts b/tests/UserManagement.test.ts new file mode 100644 index 0000000..5643781 --- /dev/null +++ b/tests/UserManagement.test.ts @@ -0,0 +1,42 @@ +import { shallowMount, mount } from '@vue/test-utils'; +import UserManagement from '../src/UserManagement.vue'; + +jest.mock('../src/hooks', () => ({ + useOptions: () => ({ projectId: 'project1', baseUrl: 'baseUrl' }), + useDescope: () => ({ httpClient: { hooks: { afterRequest: jest.fn() } } }), + useUser: () => ({}), + useSession: () => ({}) +})); + +globalThis.Response = class {}; + +describe('UserManagement.vue', () => { + it('renders the widget', () => { + const wrapper = shallowMount(UserManagement, { + props: { tenant: 'flow1' } + }); + expect(wrapper.find('descope-user-management-widget').exists()).toBe(true); + }); + + it('renders a widget with the correct props', () => { + const errorTransformer = (error: { text: string; type: string }) => { + return error.text || error.type; + }; + const wrapper = mount(UserManagement, { + props: { + tenant: 'test-tenant', + theme: 'test-theme', + locale: 'test-locale', + debug: true + } + }); + + const descopeWc = wrapper.find('descope-user-management-widget'); + expect(descopeWc.exists()).toBe(true); + expect(descopeWc.attributes('project-id')).toBe('project1'); + expect(descopeWc.attributes('base-url')).toBe('baseUrl'); + expect(descopeWc.attributes('theme')).toBe('test-theme'); + expect(descopeWc.attributes('tenant')).toBe('test-tenant'); + expect(descopeWc.attributes('debug')).toBe('true'); + }); +}); diff --git a/tests/hooks.test.ts b/tests/hooks.test.ts index c8455c3..dcb087f 100644 --- a/tests/hooks.test.ts +++ b/tests/hooks.test.ts @@ -1,6 +1,5 @@ import { inject } from 'vue'; -import { useDescope, useSession, useUser } from '../src'; -import { useOptions } from '../src/hooks'; +import { useOptions, useDescope, useSession, useUser } from '../src/hooks'; jest.mock('vue', () => ({ ...jest.requireActual('vue'), diff --git a/tests/plugin.test.ts b/tests/plugin.test.ts index c80a8f7..7a292ad 100644 --- a/tests/plugin.test.ts +++ b/tests/plugin.test.ts @@ -1,4 +1,4 @@ -import plugin, { routeGuard } from '../src'; +import plugin, { routeGuard } from '../src/plugin'; import createSdk from '@descope/web-js-sdk'; jest.mock('@descope/web-js-sdk');