Skip to content

Commit 6fea464

Browse files
feat(Streamable): Add support for Streamable (#48)
* Added support for streamable embeds * Reverting mistaken README changes * Removing last line inserted by prettier ... * Fixing up Twitter section ... * Updating to use HTML embed code from Streamable API * fixing linting * Fixing last of validation errors * Update README.md Co-Authored-By: Michaël De Boey <info@michaeldeboey.be> * Updating PR in response to code review feedback * Fixing single quote issue and updating readme * Renaming test, alphabetized kitchen sink test * Extracted mockFetch, though there is a dependency on jest usage that requires the mocking of node-fetch to occur in each test file (jestjs/jest#5993), updated tests * undo mock fetch extraction and inline expected html result * Apply suggestions from code review Co-Authored-By: Michaël De Boey <info@michaeldeboey.be> * Using URL dependency, removed extra bit from Readme * Adding test coverage for more verbose logic * Simplified shouldTransform function * Update tests * Update docs * Updating shouldTransform * Further updates to shouldTransform method * Updating to simply use array.includes * Added suggested changes * Added getNormalizedStreamableUrl function * Fixing normalized streamable URL * fix linting rule * fix * Extract normalized var * Cleanup code * Cleanup tests * Add Streamable to package.json keywords * Update iframe test Co-authored-by: Michaël De Boey <info@michaeldeboey.be>
1 parent 342c72b commit 6fea464

File tree

8 files changed

+367
-3
lines changed

8 files changed

+367
-3
lines changed

README.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
Trying to embed well known services (like [CodePen][codepen],
2222
[CodeSandbox][codesandbox], [Slides][slides], [SoundCloud][soundcloud],
23-
[Spotify][spotify], [Twitter][twitter] or [YouTube][youtube]) into your
24-
[Gatsby][gatsby] website can be hard, since you have to know how this needs to
25-
be done for all of these different services.
23+
[Spotify][spotify], [Streamable][streamable], [Twitter][twitter] or
24+
[YouTube][youtube]) into your [Gatsby][gatsby] website can be hard, since you
25+
have to know how this needs to be done for all of these different services.
2626

2727
## This solution
2828

@@ -44,6 +44,7 @@ and replace it with the proper embed-code.
4444
- [Slides](#slides)
4545
- [SoundCloud](#soundcloud)
4646
- [Spotify](#spotify)
47+
- [Streamable](#streamable)
4748
- [Twitter](#twitter)
4849
- [YouTube](#youtube)
4950
- [Custom Transformers](#custom-transformers)
@@ -184,6 +185,28 @@ https://open.spotify.com/track/0It2bnTdLl2vyymzOkBI3L
184185
></iframe>
185186
```
186187

188+
### Streamable
189+
190+
#### Usage
191+
192+
```md
193+
https://streamable.com/moo
194+
```
195+
196+
#### Result
197+
198+
```html
199+
<iframe
200+
class="streamable-embed"
201+
src="https://streamable.com/o/moo"
202+
frameborder="0"
203+
scrolling="no"
204+
width="1920"
205+
height="1080"
206+
allowfullscreen
207+
></iframe>
208+
```
209+
187210
### Twitter
188211

189212
The returned HTML snippet from the Twitter transformer will only be
@@ -414,6 +437,7 @@ MIT
414437
[slides]: https://slides.com
415438
[soundcloud]: https://soundcloud.com
416439
[spotify]: https://spotify.com
440+
[streamable]: https://streamable.com
417441
[twitter]: https://twitter.com
418442
[twitter-widget-javascript-docs]: https://developer.twitter.com/en/docs/twitter-for-websites/javascript-api/overview
419443
[youtube]: https://youtube.com

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"slides",
1616
"soundcloud",
1717
"spotify",
18+
"streamable",
1819
"twitter",
1920
"youtube"
2021
],

src/__tests__/__fixtures__/kitchensink.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ https://soundcloud.com/clemenswenners/africa
2525

2626
https://open.spotify.com/track/0It2bnTdLl2vyymzOkBI3L
2727

28+
https://streamable.com/moo
29+
2830
https://twitter.com/kentcdodds/status/1078755736455278592
2931

3032
https://youtu.be/dQw4w9WgXcQ

src/__tests__/plugin.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ describe('gatsby-remark-embedder', () => {
1414

1515
test('can transform all supported links (kitchensink)', async () => {
1616
mockCache({
17+
'https://streamable.com/moo': `<iframe class="streamable-embed-from-cache" src="https://streamable.com/o/moo" frameborder="0" scrolling="no" width="1920" height="1080" allowfullscreen></iframe>`,
1718
'https://twitter.com/kentcdodds/status/1078755736455278592': `<blockquote class="twitter-tweet-from-cache"><p lang="en" dir="ltr">example</p>&mdash; Kent C. Dodds (@kentcdodds) <a href="https://twitter.com/kentcdodds/status/1078755736455278592?ref_src=twsrc%5Etfw">December 28, 2018</a></blockquote>`,
1819
});
1920
const markdownAST = getMarkdownASTForFile('kitchensink', true);
@@ -48,6 +49,8 @@ describe('gatsby-remark-embedder', () => {
4849
4950
<iframe src=\\"https://open.spotify.com/embed/track/0It2bnTdLl2vyymzOkBI3L\\" width=\\"100%\\" height=\\"380\\" frameborder=\\"0\\" allowtransparency=\\"true\\" allow=\\"encrypted-media\\"></iframe>
5051
52+
<iframe class=\\"streamable-embed-from-cache\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
53+
5154
<blockquote class=\\"twitter-tweet-from-cache\\"><p lang=\\"en\\" dir=\\"ltr\\">example</p>&mdash; Kent C. Dodds (@kentcdodds) <a href=\\"https://twitter.com/kentcdodds/status/1078755736455278592?ref_src=twsrc%5Etfw\\">December 28, 2018</a></blockquote>
5255
5356
<iframe width=\\"100%\\" height=\\"315\\" src=\\"https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ?rel=0\\" frameBorder=\\"0\\" allow=\\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\\" allowFullScreen></iframe>
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
import cases from 'jest-in-case';
2+
import fetchMock from 'node-fetch';
3+
4+
import plugin from '../../';
5+
import {
6+
getHTML,
7+
getNormalizedStreamableUrl,
8+
shouldTransform,
9+
} from '../../transformers/Streamable';
10+
11+
import { cache, getMarkdownASTForFile, parseASTToMarkdown } from '../helpers';
12+
13+
jest.mock('node-fetch', () => jest.fn());
14+
15+
const mockFetch = html =>
16+
fetchMock.mockResolvedValue({ json: () => Promise.resolve({ html }) });
17+
18+
beforeEach(() => {
19+
fetchMock.mockClear();
20+
});
21+
22+
cases(
23+
'url validation',
24+
({ url, valid }) => {
25+
expect(shouldTransform(url)).toBe(valid);
26+
},
27+
{
28+
'non-Streamable url': {
29+
url: 'https://not-a-streamable-url.com',
30+
valid: false,
31+
},
32+
"non-Streamable url ending with 'streamable.com'": {
33+
url: 'https://this-is-not-streamable.com',
34+
valid: false,
35+
},
36+
'documentation page': {
37+
url: 'https://streamable.com/documentation',
38+
valid: false,
39+
},
40+
'login page': {
41+
url: 'https://streamable.com/login',
42+
valid: false,
43+
},
44+
'recover page': {
45+
url: 'https://streamable.com/recover',
46+
valid: false,
47+
},
48+
'settings page': {
49+
url: 'https://streamable.com/settings',
50+
valid: false,
51+
},
52+
'signup page': {
53+
url: 'https://streamable.com/signup',
54+
valid: false,
55+
},
56+
"video url having '/e/' path & username & extra path": {
57+
url: 'https://streamable.com/e/moo/username/extra',
58+
valid: false,
59+
},
60+
"video url having '/g/' path & username & extra path": {
61+
url: 'https://streamable.com/g/moo/username/extra',
62+
valid: false,
63+
},
64+
"video url having '/o/' path & username & extra path": {
65+
url: 'https://streamable.com/o/moo/username/extra',
66+
valid: false,
67+
},
68+
"video url having '/s/' path & username & extra path": {
69+
url: 'https://streamable.com/s/moo/username/extra',
70+
valid: false,
71+
},
72+
"video url having '/t/' path & username & extra path": {
73+
url: 'https://streamable.com/t/moo/username/extra',
74+
valid: false,
75+
},
76+
'video url': {
77+
url: 'https://streamable.com/moo',
78+
valid: true,
79+
},
80+
"video url having '/e/' path": {
81+
url: 'https://streamable.com/e/moo',
82+
valid: true,
83+
},
84+
"video url having '/e/' path & username": {
85+
url: 'https://streamable.com/e/moo/username',
86+
valid: true,
87+
},
88+
"video url having '/g/' path": {
89+
url: 'https://streamable.com/g/moo',
90+
valid: true,
91+
},
92+
"video url having '/g/' path & username": {
93+
url: 'https://streamable.com/g/moo/username',
94+
valid: true,
95+
},
96+
"video url having '/o/' path": {
97+
url: 'https://streamable.com/o/moo',
98+
valid: true,
99+
},
100+
"video url having '/o/' path & username": {
101+
url: 'https://streamable.com/o/moo/username',
102+
valid: true,
103+
},
104+
"video url having '/s/' path": {
105+
url: 'https://streamable.com/s/moo',
106+
valid: true,
107+
},
108+
"video url having '/s/' path & username": {
109+
url: 'https://streamable.com/s/moo/username',
110+
valid: true,
111+
},
112+
"video url having '/t/' path": {
113+
url: 'https://streamable.com/t/moo',
114+
valid: true,
115+
},
116+
"video url having '/t/' path & username": {
117+
url: 'https://streamable.com/t/moo/username',
118+
valid: true,
119+
},
120+
}
121+
);
122+
123+
cases(
124+
'getNormalizedStreamableUrl',
125+
({ url, normalizedUrl }) => {
126+
expect(getNormalizedStreamableUrl(url)).toBe(normalizedUrl);
127+
},
128+
{
129+
'video url': {
130+
url: 'https://streamable.com/moo',
131+
normalizedUrl: 'https://streamable.com/moo',
132+
},
133+
"video url having '/e/' path": {
134+
url: 'https://streamable.com/e/moo',
135+
normalizedUrl: 'https://streamable.com/moo',
136+
},
137+
"video url having '/e/' path & username": {
138+
url: 'https://streamable.com/e/moo/username',
139+
normalizedUrl: 'https://streamable.com/moo',
140+
},
141+
"video url having '/g/' path": {
142+
url: 'https://streamable.com/g/moo',
143+
normalizedUrl: 'https://streamable.com/moo',
144+
},
145+
"video url having '/g/' path & username": {
146+
url: 'https://streamable.com/g/moo/username',
147+
normalizedUrl: 'https://streamable.com/moo',
148+
},
149+
"video url having '/o/' path": {
150+
url: 'https://streamable.com/o/moo',
151+
normalizedUrl: 'https://streamable.com/moo',
152+
},
153+
"video url having '/o/' path & username": {
154+
url: 'https://streamable.com/o/moo/username',
155+
normalizedUrl: 'https://streamable.com/moo',
156+
},
157+
"video url having '/s/' path": {
158+
url: 'https://streamable.com/s/moo',
159+
normalizedUrl: 'https://streamable.com/moo',
160+
},
161+
"video url having '/s/' path & username": {
162+
url: 'https://streamable.com/s/moo/username',
163+
normalizedUrl: 'https://streamable.com/moo',
164+
},
165+
"video url having '/t/' path": {
166+
url: 'https://streamable.com/t/moo',
167+
normalizedUrl: 'https://streamable.com/moo',
168+
},
169+
"video url having '/t/' path & username": {
170+
url: 'https://streamable.com/t/moo/username',
171+
normalizedUrl: 'https://streamable.com/moo',
172+
},
173+
}
174+
);
175+
176+
test('Gets the correct Streamable iframe', async () => {
177+
mockFetch(
178+
`<iframe class="streamable-embed-mocked-fetch-transformer" src="https://streamable.com/o/moo" frameborder="0" scrolling="no" width="1920" height="1080" allowfullscreen></iframe>`
179+
);
180+
const html = await getHTML('https://streamable.com/moo');
181+
182+
expect(html).toMatchInlineSnapshot(
183+
`"<iframe class=\\"streamable-embed-mocked-fetch-transformer\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>"`
184+
);
185+
});
186+
187+
test('Plugin correctly transforms Streamable links', async () => {
188+
mockFetch(
189+
`<iframe class="streamable-embed-mocked-fetch-plugin" src="https://streamable.com/o/moo" frameborder="0" scrolling="no" width="1920" height="1080" allowfullscreen></iframe>`
190+
);
191+
const markdownAST = getMarkdownASTForFile('Streamable');
192+
193+
const processedAST = await plugin({ cache, markdownAST });
194+
195+
expect(parseASTToMarkdown(processedAST)).toMatchInlineSnapshot(`
196+
"<https://not-a-streamable-url.com>
197+
198+
<https://this-is-not-streamable.com>
199+
200+
<https://streamable.com/documentation>
201+
202+
<https://streamable.com/login>
203+
204+
<https://streamable.com/recover>
205+
206+
<https://streamable.com/settings>
207+
208+
<https://streamable.com/signup>
209+
210+
<https://streamable.com/e/moo/username/extra>
211+
212+
<https://streamable.com/g/moo/username/extra>
213+
214+
<https://streamable.com/o/moo/username/extra>
215+
216+
<https://streamable.com/s/moo/username/extra>
217+
218+
<https://streamable.com/t/moo/username/extra>
219+
220+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
221+
222+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
223+
224+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
225+
226+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
227+
228+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
229+
230+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
231+
232+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
233+
234+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
235+
236+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
237+
238+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
239+
240+
<iframe class=\\"streamable-embed-mocked-fetch-plugin\\" src=\\"https://streamable.com/o/moo\\" frameborder=\\"0\\" scrolling=\\"no\\" width=\\"1920\\" height=\\"1080\\" allowfullscreen></iframe>
241+
"
242+
`);
243+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
https://not-a-streamable-url.com
2+
3+
https://this-is-not-streamable.com
4+
5+
https://streamable.com/documentation
6+
7+
https://streamable.com/login
8+
9+
https://streamable.com/recover
10+
11+
https://streamable.com/settings
12+
13+
https://streamable.com/signup
14+
15+
https://streamable.com/e/moo/username/extra
16+
17+
https://streamable.com/g/moo/username/extra
18+
19+
https://streamable.com/o/moo/username/extra
20+
21+
https://streamable.com/s/moo/username/extra
22+
23+
https://streamable.com/t/moo/username/extra
24+
25+
https://streamable.com/moo
26+
27+
https://streamable.com/e/moo
28+
29+
https://streamable.com/e/moo/username
30+
31+
https://streamable.com/g/moo
32+
33+
https://streamable.com/g/moo/username
34+
35+
https://streamable.com/o/moo
36+
37+
https://streamable.com/o/moo/username
38+
39+
https://streamable.com/s/moo
40+
41+
https://streamable.com/s/moo/username
42+
43+
https://streamable.com/t/moo
44+
45+
https://streamable.com/t/moo/username

0 commit comments

Comments
 (0)