@clappr/player 0.12.10 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clappr/player",
3
- "version": "0.12.10",
3
+ "version": "0.14.0",
4
4
  "description": "An extensible media player for the web",
5
5
  "main": "dist/clappr.js",
6
6
  "scripts": {
@@ -8,9 +8,10 @@
8
8
  "bundle-check": "ANALYZE_BUNDLE=true rollup --config --bundleConfigAsCjs",
9
9
  "lint": "eslint *.js src/",
10
10
  "lint:fix": "npm run lint -- --fix",
11
- "release": "MINIMIZE=true rollup --config --bundleConfigAsCjs",
11
+ "release": "rm -rf dist && MINIMIZE=true rollup --config --bundleConfigAsCjs",
12
12
  "start": "DEV=true rollup --config --bundleConfigAsCjs --watch",
13
13
  "test": "echo 'No tests configured. This project is only for bundling the player components.'",
14
+ "test:smoke": "jest ./src/dist.smoke.test.js --testPathIgnorePatterns=/node_modules/ --silent",
14
15
  "watch": "rollup --config --bundleConfigAsCjs --watch",
15
16
  "prepublishOnly": "lerna run release --scope=@clappr/player"
16
17
  },
@@ -33,10 +34,11 @@
33
34
  },
34
35
  "homepage": "https://github.com/clappr/clappr",
35
36
  "devDependencies": {
36
- "@clappr/core": "^0.14.8",
37
- "@clappr/hlsjs-playback": "^2.0.0",
38
- "@clappr/plugins": "^0.9.8",
37
+ "@clappr/core": "^0.16.0",
38
+ "@clappr/hlsjs-playback": "^3.0.0",
39
+ "@clappr/plugins": "^0.9.10",
39
40
  "@rollup/plugin-replace": "^2.4.2",
41
+ "hls.js": "^1",
40
42
  "rollup-plugin-filesize": "^9.1.1",
41
43
  "rollup-plugin-serve": "^1.1.0"
42
44
  },
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Smoke-tests the published dist/ artifacts. The player bundle embeds core,
3
+ * plugins and playbacks, so identity checks are against the same module.
4
+ */
5
+ const fs = require('fs')
6
+ const path = require('path')
7
+ const vm = require('vm')
8
+ const { TextEncoder, TextDecoder } = require('util')
9
+
10
+ // jest-environment-jsdom omits these; must run before the require below —
11
+ // jsdom's whatwg-url throws on load without TextEncoder/TextDecoder.
12
+ global.TextEncoder = global.TextEncoder || TextEncoder
13
+ global.TextDecoder = global.TextDecoder || TextDecoder
14
+ const { JSDOM } = require('jsdom')
15
+ const { expectNoNativeClasses, expectEs5Subclassable } = require('../../../test/dist-contract')
16
+
17
+ const DIST = path.join(__dirname, '..', 'dist')
18
+ const pkg = require('../package.json')
19
+
20
+ const ARTIFACTS = {
21
+ main: 'clappr.js',
22
+ mainMin: 'clappr.min.js',
23
+ plainhtml5: 'clappr.plainhtml5.js',
24
+ plainhtml5Min: 'clappr.plainhtml5.min.js'
25
+ }
26
+
27
+ const FULL_PLAYER = [ARTIFACTS.main, ARTIFACTS.mainMin]
28
+ const PLAINHTML5 = [ARTIFACTS.plainhtml5, ARTIFACTS.plainhtml5Min]
29
+ const UMD_ARTIFACTS = Object.values(ARTIFACTS)
30
+
31
+ // Demo-only unminified entry: no map per AGENTS.md sourcemap policy.
32
+ const EXPECTED_SOURCEMAPS = [
33
+ 'clappr.js.map',
34
+ 'clappr.min.js.map',
35
+ 'clappr.plainhtml5.min.js.map'
36
+ ].sort()
37
+
38
+ function readArtifact(name) {
39
+ return fs.readFileSync(path.join(DIST, name), 'utf8')
40
+ }
41
+
42
+ function loadArtifact(name) {
43
+ jest.resetModules()
44
+ return require(path.join(DIST, name))
45
+ }
46
+
47
+ function resolveClappr(mod) {
48
+ return mod.default || mod
49
+ }
50
+
51
+ function loadUmdInSandbox(filename, { amd = false } = {}) {
52
+ const code = readArtifact(filename)
53
+ const dom = new JSDOM('<!doctype html><html><body></body></html>', {
54
+ url: 'http://localhost/',
55
+ pretendToBeVisual: true,
56
+ runScripts: 'outside-only'
57
+ })
58
+ const sandbox = dom.getInternalVMContext()
59
+
60
+ let amdExports
61
+ if (amd) {
62
+ sandbox.define = (depsOrFactory, maybeFactory) => {
63
+ if (typeof depsOrFactory === 'function') {
64
+ amdExports = depsOrFactory()
65
+ return
66
+ }
67
+ const factory = maybeFactory
68
+ const args = depsOrFactory.map(dep => {
69
+ if (dep === 'exports') {
70
+ amdExports = {}
71
+ return amdExports
72
+ }
73
+ return undefined
74
+ })
75
+ factory(...args)
76
+ }
77
+ sandbox.define.amd = {}
78
+ }
79
+
80
+ vm.runInContext(code, sandbox, { filename: path.join(DIST, filename) })
81
+ return { sandbox, amdExports }
82
+ }
83
+
84
+ function prototypeChainContains(pluginProto, baseProto) {
85
+ let proto = pluginProto
86
+ while (proto) {
87
+ if (proto === baseProto) return true
88
+ proto = Object.getPrototypeOf(proto)
89
+ }
90
+ return false
91
+ }
92
+
93
+ function assertSharedBundleContract(C) {
94
+ expect(C.version).toBe(pkg.version)
95
+
96
+ const bases = [
97
+ C.ContainerPlugin.prototype,
98
+ C.CorePlugin.prototype,
99
+ C.UIContainerPlugin.prototype,
100
+ C.UICorePlugin.prototype
101
+ ]
102
+
103
+ for (const Plugin of Object.values(C.Plugins)) {
104
+ expect(typeof Plugin).toBe('function')
105
+ const matchesBase = bases.some(base =>
106
+ prototypeChainContains(Object.getPrototypeOf(Plugin.prototype), base)
107
+ )
108
+ expect(matchesBase).toBe(true)
109
+ }
110
+ }
111
+
112
+ function assertSourceMappingURL(filename) {
113
+ expect(readArtifact(filename)).toContain(`sourceMappingURL=${filename}.map`)
114
+ }
115
+
116
+ describe.each([
117
+ ['main UMD', ARTIFACTS.main],
118
+ ['main UMD minified', ARTIFACTS.mainMin],
119
+ ['plainhtml5 UMD', ARTIFACTS.plainhtml5],
120
+ ['plainhtml5 UMD minified', ARTIFACTS.plainhtml5Min]
121
+ ])('%s (%s)', (_label, filename) => {
122
+ test('exports plugins that extend the same-bundle plugin bases', () => {
123
+ assertSharedBundleContract(resolveClappr(loadArtifact(filename)))
124
+ })
125
+
126
+ test('plugin bases are ES5-subclassable', () => {
127
+ // Behavioral contract for full + plainhtml5: third-party ES5 plugins call
128
+ // Parent.call(this, ...) on these bases (#2540). Syntax scan below cannot
129
+ // cover full clappr(.min).js — embedded hls.js ships native classes.
130
+ const C = resolveClappr(loadArtifact(filename))
131
+ expectEs5Subclassable(C.BaseObject)
132
+ expectEs5Subclassable(C.UIObject)
133
+ expectEs5Subclassable(C.UICorePlugin, { options: {} })
134
+ })
135
+ })
136
+
137
+ describe('full player HLS', () => {
138
+ test.each(FULL_PLAYER)('%s HLS extends HTML5Video', filename => {
139
+ const C = resolveClappr(loadArtifact(filename))
140
+ expect(Object.getPrototypeOf(C.HLS.prototype)).toBe(C.HTML5Video.prototype)
141
+ })
142
+
143
+ test.each(FULL_PLAYER)('%s embeds its own hls.js copy', filename => {
144
+ const C = resolveClappr(loadArtifact(filename))
145
+ expect(C.HLS.HLSJS).toBeDefined()
146
+ expect(C.HLS.HLSJS).not.toBe(require('hls.js'))
147
+ })
148
+ })
149
+
150
+ describe('plainhtml5 bundle', () => {
151
+ test.each(PLAINHTML5)('%s has no HLS', filename => {
152
+ const C = resolveClappr(loadArtifact(filename))
153
+ expect(C.HLS).toBeUndefined()
154
+ })
155
+
156
+ // Syntax-only on plainhtml5: full player embeds hls.js (native class). ES5
157
+ // subclassability of Clappr bases is asserted for all artifacts above.
158
+ test.each(PLAINHTML5)('%s does not emit native class syntax', filename => {
159
+ expectNoNativeClasses(readArtifact(filename))
160
+ })
161
+ })
162
+
163
+ describe('UMD global and AMD branches', () => {
164
+ test.each(UMD_ARTIFACTS)('%s sets global Clappr without an AMD loader', filename => {
165
+ const { sandbox } = loadUmdInSandbox(filename, { amd: false })
166
+ expect(typeof sandbox.Clappr).toBe('object')
167
+ expect(typeof sandbox.Clappr.Player).toBe('function')
168
+ })
169
+
170
+ test.each(UMD_ARTIFACTS)('%s does not set global Clappr when define.amd is present', filename => {
171
+ const { sandbox, amdExports } = loadUmdInSandbox(filename, { amd: true })
172
+ expect(sandbox.Clappr).toBeUndefined()
173
+ expect(typeof amdExports.Player).toBe('function')
174
+ })
175
+ })
176
+
177
+ describe('sourcemap comments', () => {
178
+ test.each([ARTIFACTS.main, ARTIFACTS.mainMin, ARTIFACTS.plainhtml5Min])(
179
+ '%s publishes a sourcemap comment',
180
+ filename => {
181
+ assertSourceMappingURL(filename)
182
+ }
183
+ )
184
+ })
185
+
186
+ describe('dist sourcemap inventory', () => {
187
+ test('ships exactly the expected .map files', () => {
188
+ const maps = fs
189
+ .readdirSync(DIST)
190
+ .filter(f => f.endsWith('.map'))
191
+ .sort()
192
+ expect(maps).toEqual(EXPECTED_SOURCEMAPS)
193
+ })
194
+ })