diff --git a/.github/allowed-actions.js b/.github/allowed-actions.js
index 8c907b54a1..8f08371ea1 100644
--- a/.github/allowed-actions.js
+++ b/.github/allowed-actions.js
@@ -31,7 +31,7 @@ module.exports = [
'rachmari/actions-add-new-issue-to-column@1a459ef92308ba7c9c9dc2fcdd72f232495574a9',
'rachmari/labeler@832d42ec5523f3c6d46e8168de71cd54363e3e2e',
'repo-sync/github-sync@3832fe8e2be32372e1b3970bbae8e7079edeec88',
- 'repo-sync/pull-request@ea6773388b83b337e4da9a223293309f2c3670e7',
+ 'repo-sync/pull-request@33777245b1aace1a58c87a29c90321aa7a74bd7d',
'rtCamp/action-slack-notify@e17352feaf9aee300bf0ebc1dfbf467d80438815',
'tjenkinson/gh-action-auto-merge-dependency-updates@cee2ac0'
]
diff --git a/.github/workflows/repo-freeze-reminders.yml b/.github/workflows/repo-freeze-reminders.yml
new file mode 100644
index 0000000000..be29ec5553
--- /dev/null
+++ b/.github/workflows/repo-freeze-reminders.yml
@@ -0,0 +1,24 @@
+name: Repo Freeze Reminders
+
+on:
+ schedule:
+ - cron: "00 11 * * *" # once per day around 11:00am UTC
+
+env:
+ FREEZE: ${{ secrets.FREEZE }}
+
+jobs:
+ check-freezer:
+ name: Remind about deployment freezes
+ runs-on: ubuntu-latest
+ steps:
+
+ - name: Send Slack notification if repo is frozen
+ if: ${{ env.FREEZE == 'true' }}
+ uses: rtCamp/action-slack-notify@e17352feaf9aee300bf0ebc1dfbf467d80438815
+ env:
+ SLACK_WEBHOOK: ${{ secrets.DOCS_ALERTS_SLACK_WEBHOOK }}
+ SLACK_USERNAME: docs-repo-sync
+ SLACK_ICON_EMOJI: ':freezing_face:'
+ SLACK_COLOR: '#51A0D5' # Carolina Blue
+ SLACK_MESSAGE: All repo-sync runs will fail for ${{ github.repository }} because the repo is currently frozen!
diff --git a/.github/workflows/repo-sync.yml b/.github/workflows/repo-sync.yml
index a44dbbe371..ae0c9514af 100644
--- a/.github/workflows/repo-sync.yml
+++ b/.github/workflows/repo-sync.yml
@@ -14,8 +14,8 @@ env:
FREEZE: ${{ secrets.FREEZE }}
jobs:
- repo-sync:
- name: Repo Sync
+ check-freezer:
+ name: Check for deployment freezes
runs-on: ubuntu-latest
steps:
@@ -25,6 +25,12 @@ jobs:
echo 'The repo is currently frozen! Exiting this workflow.'
exit 1 # prevents further steps from running
+ repo-sync:
+ name: Repo Sync
+ needs: check-freezer
+ runs-on: ubuntu-latest
+ steps:
+
- name: Check out repo
uses: actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675
@@ -39,7 +45,7 @@ jobs:
github_token: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
- name: Create pull request
- uses: repo-sync/pull-request@ea6773388b83b337e4da9a223293309f2c3670e7
+ uses: repo-sync/pull-request@33777245b1aace1a58c87a29c90321aa7a74bd7d
env:
GITHUB_TOKEN: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
with:
@@ -56,6 +62,7 @@ jobs:
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
branch: repo-sync
+ base: main
- name: Approve pull request
if: ${{ steps.find-pull-request.outputs.number }}
@@ -66,7 +73,10 @@ jobs:
- name: Send Slack notification if workflow fails
uses: rtCamp/action-slack-notify@e17352feaf9aee300bf0ebc1dfbf467d80438815
- if: failure()
+ if: ${{ failure() }}
env:
SLACK_WEBHOOK: ${{ secrets.DOCS_ALERTS_SLACK_WEBHOOK }}
+ SLACK_USERNAME: docs-repo-sync
+ SLACK_ICON_EMOJI: ':ohno:'
+ SLACK_COLOR: '#B90E0A' # Crimson
SLACK_MESSAGE: The last repo-sync run for ${{github.repository}} failed. See https://github.com/${{github.repository}}/actions?query=workflow%3A%22Repo+Sync%22
diff --git a/content/developers/apps/installing-github-apps.md b/content/developers/apps/installing-github-apps.md
index efa6d27ffd..8f49ffeba6 100644
--- a/content/developers/apps/installing-github-apps.md
+++ b/content/developers/apps/installing-github-apps.md
@@ -55,7 +55,7 @@ These steps assume you have [built a {% data variables.product.prodname_github_a
You can simplify the authorization process by completing it during app installation. To do this, select **Request user authorization (OAuth) during installation** when creating or modifying your app in GitHub. See "[Creating a GitHub App](/apps/building-github-apps/creating-a-github-app/)" to learn more.
-Once someone has installed your app, you will need to get an access token for the user. See steps 2 and 3 in "[Identifying a users on your site](/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps/#identifying-users-on-your-site)" to learn more.
+Once someone has installed your app, you will need to get an access token for the user. See steps 2 and 3 in "[Identifying users on your site](/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps/#identifying-users-on-your-site)" to learn more.
### Preserving an application state during installation
You can provide a `state` parameter in an app's installation URL to preserve the state of the application page and return people back to that state after they install, authenticate, or accept updates to your GitHub App. For example, you could use the `state` to correlate an installation to a user or account.
diff --git a/content/github/collaborating-with-issues-and-pull-requests/syncing-a-fork.md b/content/github/collaborating-with-issues-and-pull-requests/syncing-a-fork.md
index 458bfa66d6..a3d3ac7f76 100644
--- a/content/github/collaborating-with-issues-and-pull-requests/syncing-a-fork.md
+++ b/content/github/collaborating-with-issues-and-pull-requests/syncing-a-fork.md
@@ -20,16 +20,16 @@ Before you can sync your fork with an upstream repository, you must [configure a
> remote: Total 62 (delta 27), reused 44 (delta 9)
> Unpacking objects: 100% (62/62), done.
> From https://{% data variables.command_line.codeblock %}/ORIGINAL_OWNER/ORIGINAL_REPOSITORY
- > * [new branch] master -> upstream/master
+ > * [new branch] main -> upstream/main
```
-4. Check out your fork's local `master` branch.
+4. Check out your fork's local `main` branch.
```shell
- $ git checkout master
- > Switched to branch 'master'
+ $ git checkout main
+ > Switched to branch 'main'
```
-5. Merge the changes from `upstream/master` into your local `master` branch. This brings your fork's `master` branch into sync with the upstream repository, without losing your local changes.
+5. Merge the changes from `upstream/main` into your local `main` branch. This brings your fork's `main` branch into sync with the upstream repository, without losing your local changes.
```shell
- $ git merge upstream/master
+ $ git merge upstream/main
> Updating a422352..5fdff0f
> Fast-forward
> README | 9 -------
@@ -39,7 +39,7 @@ Before you can sync your fork with an upstream repository, you must [configure a
> create mode 100644 README.md
``` If your local branch didn't have any unique commits, Git will instead perform a "fast-forward":
```shell
- $ git merge upstream/master
+ $ git merge upstream/main
> Updating 34e91da..16c56ad
> Fast-forward
> README.md | 5 +++--
diff --git a/content/github/finding-security-vulnerabilities-and-errors-in-your-code/managing-code-scanning-alerts-for-your-repository.md b/content/github/finding-security-vulnerabilities-and-errors-in-your-code/managing-code-scanning-alerts-for-your-repository.md
index 1d48dd897e..523b1ecc5e 100644
--- a/content/github/finding-security-vulnerabilities-and-errors-in-your-code/managing-code-scanning-alerts-for-your-repository.md
+++ b/content/github/finding-security-vulnerabilities-and-errors-in-your-code/managing-code-scanning-alerts-for-your-repository.md
@@ -56,7 +56,7 @@ Alerts may be fixed in one branch but not in another. You can use the "Branch" d
### Dismissing or deleting alerts
-There are two ways of closing an alert. You can fix the problem in the code, or you can dismiss the alert. Alternatively, you can delete alerts. Deleting alerts is useful in situations where you have enabled a {% data variables.product.prodname_code_scanning %} tool and then decided to remove it, or where you have enabled {% data variables.product.prodname_codeql %} analysis with a larger set of queries than you want to continue using, and you've then removed some queries from the tool. In both cases, deleting alerts allows you to clean up your {% data variables.product.prodname_code_scanning %} results. You can delete alerts from the summary list within the **Security** tab.
+There are two ways of closing an alert. You can fix the problem in the code, or you can dismiss the alert. Alternatively, if you have admin permissions for the repository, you can delete alerts. Deleting alerts is useful in situations where you have enabled a {% data variables.product.prodname_code_scanning %} tool and then decided to remove it, or where you have enabled {% data variables.product.prodname_codeql %} analysis with a larger set of queries than you want to continue using, and you've then removed some queries from the tool. In both cases, deleting alerts allows you to clean up your {% data variables.product.prodname_code_scanning %} results. You can delete alerts from the summary list within the **Security** tab.
Dismissing an alert is a way of closing an alert that you don't think needs to be fixed. {% data reusables.code-scanning.close-alert-examples %} You can dismiss alerts from {% data variables.product.prodname_code_scanning %} annotations in code, or from the summary list within the **Security** tab.
@@ -81,7 +81,7 @@ To dismiss or delete alerts:
{% data reusables.repositories.sidebar-security %}
{% data reusables.repositories.sidebar-code-scanning-alerts %}
-1. If you want to delete alerts for this {% data variables.product.prodname_code_scanning %} tool, select some or all of the check boxes and click **Delete**.
+1. If you have admin permissions for the repository, and you want to delete alerts for this {% data variables.product.prodname_code_scanning %} tool, select some or all of the check boxes and click **Delete**.

diff --git a/content/github/site-policy/github-enterprise-subscription-agreement.md b/content/github/site-policy/github-enterprise-subscription-agreement.md
index 282aaae2b5..f7dd7bff7b 100644
--- a/content/github/site-policy/github-enterprise-subscription-agreement.md
+++ b/content/github/site-policy/github-enterprise-subscription-agreement.md
@@ -330,7 +330,7 @@ The look and feel of the Service is copyright © GitHub, Inc. All rights reserve
#### 3.5.2 Copyright Infringement and DMCA Policy.
-If Customer is a copyright owner and believes that Content on the Service violates Customer’s copyright, Customer may contact GitHub in accordance with GitHub's [Digital Millenium Copyright Act Policy](https://github.com/contact/dmca) by notifying GitHub via its [DMCA Form](https://github.com/contact/dmca-notice) or by emailing copyright@github.com.
+If Customer is a copyright owner and believes that Content on the Service violates Customer’s copyright, Customer may contact GitHub in accordance with GitHub's [Digital Millennium Copyright Act Policy](https://github.com/contact/dmca) by notifying GitHub via its [DMCA Form](https://github.com/contact/dmca-notice) or by emailing copyright@github.com.
#### 3.5.3 GitHub Trademarks and Logos.
diff --git a/content/github/site-policy/github-supplemental-terms-for-microsoft-volume-licensing.md b/content/github/site-policy/github-supplemental-terms-for-microsoft-volume-licensing.md
index cd043311ef..523adeb925 100644
--- a/content/github/site-policy/github-supplemental-terms-for-microsoft-volume-licensing.md
+++ b/content/github/site-policy/github-supplemental-terms-for-microsoft-volume-licensing.md
@@ -175,7 +175,7 @@ The look and feel of the Service is copyright © GitHub, Inc. All rights reserve
#### 2.5.2 Copyright Infringement and DMCA Policy.
-If Customer is a copyright owner and believes that Content on the Service violates Customer’s copyright, Customer may contact GitHub in accordance with GitHub's [Digital Millenium Copyright Act Policy](https://github.com/contact/dmca) by notifying GitHub via its [DMCA Form](https://github.com/contact/dmca-notice) or by emailing copyright@github.com.
+If Customer is a copyright owner and believes that Content on the Service violates Customer’s copyright, Customer may contact GitHub in accordance with GitHub's [Digital Millennium Copyright Act Policy](https://github.com/contact/dmca) by notifying GitHub via its [DMCA Form](https://github.com/contact/dmca-notice) or by emailing copyright@github.com.
#### 2.5.3 GitHub Trademarks and Logos.
diff --git a/content/github/working-with-github-pages/about-github-pages-and-jekyll.md b/content/github/working-with-github-pages/about-github-pages-and-jekyll.md
index c411dae253..b4b20f3fcd 100644
--- a/content/github/working-with-github-pages/about-github-pages-and-jekyll.md
+++ b/content/github/working-with-github-pages/about-github-pages-and-jekyll.md
@@ -27,7 +27,7 @@ versions:
Jekyll is a static site generator with built-in support for {% data variables.product.prodname_pages %} and a simplified build process. Jekyll takes Markdown and HTML files and creates a complete static website based on your choice of layouts. Jekyll supports Markdown and Liquid, a templating language that loads dynamic content on your site. For more information, see [Jekyll](https://jekyllrb.com/).
-Jekyll is not officially supported for Windows. For more information, see "[Jekyll on Windows](http://jekyllrb.com/docs/windows/#installation)" in the Jekyll documenation.
+Jekyll is not officially supported for Windows. For more information, see "[Jekyll on Windows](http://jekyllrb.com/docs/windows/#installation)" in the Jekyll documentation.
We recommend using Jekyll with {% data variables.product.prodname_pages %}. If you prefer, you can use other static site generators or customize your own build process locally or on another server. For more information, see "[About {% data variables.product.prodname_pages %}](/articles/about-github-pages#static-site-generators)."
diff --git a/content/github/working-with-github-pages/setting-a-markdown-processor-for-your-github-pages-site-using-jekyll.md b/content/github/working-with-github-pages/setting-a-markdown-processor-for-your-github-pages-site-using-jekyll.md
index bc5f4c9c75..2041f63f7b 100644
--- a/content/github/working-with-github-pages/setting-a-markdown-processor-for-your-github-pages-site-using-jekyll.md
+++ b/content/github/working-with-github-pages/setting-a-markdown-processor-for-your-github-pages-site-using-jekyll.md
@@ -13,7 +13,7 @@ versions:
People with write permissions for a repository can set the Markdown processor for a {% data variables.product.prodname_pages %} site.
-{% data variables.product.prodname_pages %} supports two Markdown processors: [kramdown](http://kramdown.gettalong.org/) and {% data variables.product.prodname_dotcom %}'s own extended [CommonMark](https://commonmark.org/) processer, which is used to render {% data variables.product.prodname_dotcom %} Flavored Markdown throughout {% data variables.product.product_name %}. For more information, see "[About writing and formatting on {% data variables.product.prodname_dotcom %}](/articles/about-writing-and-formatting-on-github)."
+{% data variables.product.prodname_pages %} supports two Markdown processors: [kramdown](http://kramdown.gettalong.org/) and {% data variables.product.prodname_dotcom %}'s own extended [CommonMark](https://commonmark.org/) processor, which is used to render {% data variables.product.prodname_dotcom %} Flavored Markdown throughout {% data variables.product.product_name %}. For more information, see "[About writing and formatting on {% data variables.product.prodname_dotcom %}](/articles/about-writing-and-formatting-on-github)."
You can use {% data variables.product.prodname_dotcom %} Flavored Markdown with either processor, but only our CommonMark processor will always match the results you see on {% data variables.product.product_name %}.
diff --git a/content/insights/installing-and-configuring-github-insights/updating-github-insights.md b/content/insights/installing-and-configuring-github-insights/updating-github-insights.md
index df02d3fc47..e17b23f341 100644
--- a/content/insights/installing-and-configuring-github-insights/updating-github-insights.md
+++ b/content/insights/installing-and-configuring-github-insights/updating-github-insights.md
@@ -6,7 +6,6 @@ redirect_from:
- /github/installing-and-configuring-github-insights/updating-github-insights
permissions: 'People with read permissions to the `github/insights-releases` repository and administrative access to the application server can update {% data variables.product.prodname_insights %}.'
versions:
- free-pro-team: '*'
enterprise-server: '*'
---
diff --git a/javascripts/events.js b/javascripts/events.js
index 27a9d9b254..4a05744635 100644
--- a/javascripts/events.js
+++ b/javascripts/events.js
@@ -46,7 +46,8 @@ export function sendEvent ({
survey_email,
experiment_name,
experiment_variation,
- experiment_success
+ experiment_success,
+ clipboard_operation
}) {
const body = {
_csrf: getCsrf(),
@@ -107,7 +108,10 @@ export function sendEvent ({
// Experiment event
experiment_name,
experiment_variation,
- experiment_success
+ experiment_success,
+
+ // Clipboard event
+ clipboard_operation
}
const blob = new Blob([JSON.stringify(body)], { type: 'application/json' })
navigator.sendBeacon('/events', blob)
@@ -170,6 +174,13 @@ export default function initializeEvents () {
page_render_duration: render
})
+ // Clipboard event
+ ;['copy', 'cut', 'paste'].forEach(verb => {
+ document.documentElement.addEventListener(verb, () => {
+ sendEvent({ type: 'clipboard', clipboard_operation: verb })
+ })
+ })
+
// Link event
document.documentElement.addEventListener('click', evt => {
const link = evt.target.closest('a[href^="http"]')
diff --git a/lib/hydro.js b/lib/hydro.js
index df06602ae5..6ef062e7e7 100644
--- a/lib/hydro.js
+++ b/lib/hydro.js
@@ -8,7 +8,10 @@ const SCHEMAS = {
search: 'docs.v0.SearchEvent',
navigate: 'docs.v0.NavigateEvent',
survey: 'docs.v0.SurveyEvent',
- experiment: 'docs.v0.ExperimentEvent'
+ experiment: 'docs.v0.ExperimentEvent',
+ redirect: 'docs.v0.RedirectEvent',
+ clipboard: 'docs.v0.ClipboardEvent',
+ print: 'docs.v0.PrintEvent'
}
module.exports = class Hydro {
diff --git a/lib/page.js b/lib/page.js
index fe35a86351..ef77844b6d 100644
--- a/lib/page.js
+++ b/lib/page.js
@@ -6,6 +6,7 @@ const patterns = require('./patterns')
const getMapTopicContent = require('./get-map-topic-content')
const rewriteAssetPathsToS3 = require('./rewrite-asset-paths-to-s3')
const rewriteLocalLinks = require('./rewrite-local-links')
+const getApplicableVersions = require('./get-applicable-versions')
const encodeBracketedParentheticals = require('./encode-bracketed-parentheticals')
const generateRedirectsForPermalinks = require('./redirects/permalinks')
const getEnglishHeadings = require('./get-english-headings')
@@ -67,6 +68,15 @@ class Page {
delete this.popularLinks
delete this.guideLinks
+ // a page should only be available in versions that its parent product is available in
+ const versionsParentProductIsNotAvailableIn = getApplicableVersions(this.versions, this.fullPath)
+ // only the homepage will not have this.parentProduct
+ .filter(availableVersion => this.parentProduct && !this.parentProduct.versions.includes(availableVersion))
+
+ if (versionsParentProductIsNotAvailableIn.length && this.languageCode === 'en') {
+ throw new Error(`\`versions\` frontmatter in ${this.fullPath} contains ${versionsParentProductIsNotAvailableIn}, which ${this.parentProduct.id} product is not available in!`)
+ }
+
// derive array of Permalink objects
this.permalinks = Permalink.derive(this.languageCode, this.relativePath, this.title, this.versions)
@@ -95,10 +105,12 @@ class Page {
if (id === 'index.md') return null
// make sure the ID is valid
- assert(
- Object.keys(products).includes(id),
- `page ${this.fullPath} has an invalid product ID: ${id}`
- )
+ if (process.env.NODE_ENV !== 'test') {
+ assert(
+ Object.keys(products).includes(id),
+ `page ${this.fullPath} has an invalid product ID: ${id}`
+ )
+ }
return id
}
diff --git a/lib/schema-event.js b/lib/schema-event.js
index 801bf8249c..bf7fcb429e 100644
--- a/lib/schema-event.js
+++ b/lib/schema-event.js
@@ -300,6 +300,69 @@ const experimentSchema = {
}
}
+const redirectSchema = {
+ additionalProperties: false,
+ required: [
+ 'type',
+ 'context',
+ 'redirect_from',
+ 'redirect_to'
+ ],
+ properties: {
+ context,
+ type: {
+ type: 'string',
+ pattern: '^redirect$'
+ },
+ redirect_from: {
+ type: 'string',
+ description: 'The requested href.',
+ format: 'uri-reference'
+ },
+ redirect_to: {
+ type: 'string',
+ description: 'The destination href of the redirect.',
+ format: 'uri-reference'
+ }
+ }
+}
+
+const clipboardSchema = {
+ additionalProperties: false,
+ required: [
+ 'type',
+ 'context',
+ 'clipboard_operation'
+ ],
+ properties: {
+ context,
+ type: {
+ type: 'string',
+ pattern: '^clipboard$'
+ },
+ clipboard_operation: {
+ type: 'string',
+ description: 'Which clipboard operation the user is performing.',
+ enum: ['copy', 'paste', 'cut']
+ }
+ }
+}
+
+const printSchema = {
+ additionalProperties: false,
+ required: [
+ 'type',
+ 'context'
+ ],
+ properties: {
+ context,
+ type: {
+ type: 'string',
+ pattern: '^print$'
+ }
+ }
+}
+
module.exports = {
oneOf: [
pageSchema,
@@ -308,6 +371,9 @@ module.exports = {
searchSchema,
navigateSchema,
surveySchema,
- experimentSchema
+ experimentSchema,
+ redirectSchema,
+ clipboardSchema,
+ printSchema
]
}
diff --git a/tests/fixtures/products/admin/some-category/some-article-with-mismatched-versions-frontmatter.md b/tests/fixtures/products/admin/some-category/some-article-with-mismatched-versions-frontmatter.md
new file mode 100644
index 0000000000..1514631509
--- /dev/null
+++ b/tests/fixtures/products/admin/some-category/some-article-with-mismatched-versions-frontmatter.md
@@ -0,0 +1,6 @@
+---
+title: Some GitHub article
+versions:
+ free-pro-team: '*'
+ enterprise-server: '*'
+---
diff --git a/tests/links-and-images/developer-links-and-images.js b/tests/links-and-images/developer-links-and-images.js
index e323098535..42c2a3af98 100644
--- a/tests/links-and-images/developer-links-and-images.js
+++ b/tests/links-and-images/developer-links-and-images.js
@@ -9,6 +9,8 @@ const { getVersionedPathWithLanguage } = require('../../lib/path-utils')
const renderContent = require('../../lib/render-content')
const checkImages = require('../../lib/check-images')
const checkLinks = require('../../lib/check-developer-links')
+const enterpriseServerVersions = Object.keys(require('../../lib/all-versions'))
+ .filter(version => version.startsWith('enterprise-server@'))
const { getOldVersionFromNewVersion } = require('../../lib/old-versions-utils')
// schema-derived data to add to context object
@@ -64,6 +66,7 @@ describe('page rendering', () => {
page.version = pageVersion
context.page = page
context.currentVersion = pageVersion
+ context.enterpriseServerVersions = enterpriseServerVersions
const relevantPermalink = page.permalinks.find(permalink => permalink.pageVersion === pageVersion)
diff --git a/tests/links-and-images/links-and-images.js b/tests/links-and-images/links-and-images.js
index 031425f41c..4eb607f80a 100644
--- a/tests/links-and-images/links-and-images.js
+++ b/tests/links-and-images/links-and-images.js
@@ -5,6 +5,8 @@ const getApplicableVersions = require('../../lib/get-applicable-versions')
const renderContent = require('../../lib/render-content')
const checkImages = require('../../lib/check-images')
const checkLinks = require('../../lib/check-links')
+const enterpriseServerVersions = Object.keys(require('../../lib/all-versions'))
+ .filter(version => version.startsWith('enterprise-server@'))
const flat = require('flat')
const { last } = require('lodash')
@@ -56,6 +58,7 @@ describe('page rendering', () => {
page.version = pageVersion
context.page = page
context.currentVersion = pageVersion
+ context.enterpriseServerVersions = enterpriseServerVersions
// collect elements of the page that may contain links
const pageContent = page.intro + page.permissions + page.markdown
diff --git a/tests/rendering/events.js b/tests/rendering/events.js
index 3f1950ae47..e7912ee80c 100644
--- a/tests/rendering/events.js
+++ b/tests/rendering/events.js
@@ -411,4 +411,52 @@ describe('POST /events', () => {
checkEvent({ ...experimentExample, experiment_success: undefined }, 201)
)
})
+
+ describe('redirect', () => {
+ const redirectExample = {
+ ...baseExample,
+ type: 'redirect',
+ redirect_from: 'http://example.com/a',
+ redirect_to: 'http://example.com/b'
+ }
+
+ it('should record an redirect event', () =>
+ checkEvent(redirectExample, 201)
+ )
+
+ it('redirect_from is required url', () =>
+ checkEvent({ ...redirectExample, redirect_from: ' ' }, 400)
+ )
+
+ it('redirect_to is required url', () =>
+ checkEvent({ ...redirectExample, redirect_to: undefined }, 400)
+ )
+ })
+
+ describe('clipboard', () => {
+ const clipboardExample = {
+ ...baseExample,
+ type: 'clipboard',
+ clipboard_operation: 'copy'
+ }
+
+ it('should record an clipboard event', () =>
+ checkEvent(clipboardExample, 201)
+ )
+
+ it('clipboard_operation is required copy, paste, cut', () =>
+ checkEvent({ ...clipboardExample, clipboard_operation: 'destroy' }, 400)
+ )
+ })
+
+ describe('print', () => {
+ const printExample = {
+ ...baseExample,
+ type: 'print'
+ }
+
+ it('should record a print event', () =>
+ checkEvent(printExample, 201)
+ )
+ })
})
diff --git a/tests/unit/page.js b/tests/unit/page.js
index 5b3da5a5dd..876b9ca31a 100644
--- a/tests/unit/page.js
+++ b/tests/unit/page.js
@@ -365,4 +365,16 @@ describe('catches errors thrown in Page class', () => {
expect(getPage).toThrowError('versions')
})
+
+ test('page with a version in frontmatter that its parent product is not available in', () => {
+ function getPage () {
+ return new Page({
+ relativePath: 'admin/some-category/some-article-with-mismatched-versions-frontmatter.md',
+ basePath: path.join(__dirname, '../fixtures/products'),
+ languageCode: 'en'
+ })
+ }
+
+ expect(getPage).toThrowError(/`versions` frontmatter.*? product is not available in/)
+ })
})