diff --git a/.github/workflows/connect-deploys.yml b/.github/workflows/connect-deploys.yml
new file mode 100644
index 0000000000..38cff3706c
--- /dev/null
+++ b/.github/workflows/connect-deploys.yml
@@ -0,0 +1,53 @@
+name: Connect deploy tests
+on:
+ workflow_dispatch:
+ inputs:
+ reason:
+ description: "Reason for running the tests"
+ required: false
+ type: string
+ default: ""
+ schedule:
+ - cron: "0 5 * * *"
+
+jobs:
+ test-deploys:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout Repo
+ uses: actions/checkout@v4
+
+ - name: Set Path
+ shell: bash
+ run: |
+ echo "$HOME/bin" >> $GITHUB_PATH
+
+ - name: Configure Quarto
+ uses: ./.github/workflows/actions/quarto-dev
+
+ - name: Install node (for Playwright, MECA)
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16
+
+ - name: Install Playwright Browsers
+ run: npx playwright install --with-deps
+ working-directory: ./tests/integration/playwright
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.10'
+
+ - name: Install Python dependencies
+ run: pip install rsconnect
+
+ - name: Run the tests
+ env:
+ DEPLOY_CONNECT_SERVER_URL: "https://rsc.radixu.com/"
+ DEPLOY_CONNECT_SERVER_API_KEY: "${{ secrets.DEPLOY_CONNECT_SERVER_API_KEY }}"
+ run: |
+ npx playwright test
+ working-directory: ./tests/integration/playwright/connect-integration-tests
+
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-manuscript/.gitignore b/tests/docs/playwright/connect-deploy-tests/connect-manuscript/.gitignore
new file mode 100644
index 0000000000..075b2542af
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-manuscript/.gitignore
@@ -0,0 +1 @@
+/.quarto/
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-manuscript/_quarto.yml b/tests/docs/playwright/connect-deploy-tests/connect-manuscript/_quarto.yml
new file mode 100644
index 0000000000..719e11f692
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-manuscript/_quarto.yml
@@ -0,0 +1,21 @@
+project:
+ type: manuscript
+
+manuscript:
+ article: index.qmd
+
+format:
+ html:
+ comments:
+ hypothesis: true
+ docx: default
+ jats: default
+
+ # (other formats)
+ # pdf: default
+
+execute:
+ freeze: true
+
+
+
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-manuscript/index.qmd b/tests/docs/playwright/connect-deploy-tests/connect-manuscript/index.qmd
new file mode 100644
index 0000000000..8b2ecebbbc
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-manuscript/index.qmd
@@ -0,0 +1,12 @@
+---
+title: manuscript
+authors:
+ - name: Norah James
+ affiliation: The University
+ roles: reading
+ corresponding: true
+bibliography: references.bib
+---
+
+## Section
+This is a simple placeholder for the manuscript's main document [@knuth84].
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-manuscript/references.bib b/tests/docs/playwright/connect-deploy-tests/connect-manuscript/references.bib
new file mode 100644
index 0000000000..a12d7abc39
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-manuscript/references.bib
@@ -0,0 +1,19 @@
+@article{knuth84,
+ author = {Knuth, Donald.},
+ title = {Literate Programming},
+ year = {1984},
+ issue_date = {May 1984},
+ publisher = {Oxford University Press, Inc.},
+ address = {USA},
+ volume = {27},
+ number = {2},
+ issn = {0010-4620},
+ url = {https://doi.org/10.1093/comjnl/27.2.97},
+ doi = {10.1093/comjnl/27.2.97},
+ journal = {Comput. J.},
+ month = may,
+ pages = {97–111},
+ numpages = {15}
+}
+
+
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-presentation/presentation.html b/tests/docs/playwright/connect-deploy-tests/connect-presentation/presentation.html
new file mode 100644
index 0000000000..73f6d1ad49
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-presentation/presentation.html
@@ -0,0 +1,749 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Habits
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Getting up
+
+- Turn off alarm
+- Get out of bed
+
+
+
+Breakfast
+
+- Eat eggs
+- Drink coffee
+
+
+
+
+
+Dinner
+
+- Eat spaghetti
+- Drink wine
+
+
+
+Going to sleep
+
+- Get in bed
+- Count sheep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-presentation/presentation.qmd b/tests/docs/playwright/connect-deploy-tests/connect-presentation/presentation.qmd
new file mode 100644
index 0000000000..756e2990db
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-presentation/presentation.qmd
@@ -0,0 +1,29 @@
+---
+title: "Habits"
+author: "Jane Doe"
+format: revealjs
+---
+
+# In the morning
+
+## Getting up
+
+- Turn off alarm
+- Get out of bed
+
+## Breakfast
+
+- Eat eggs
+- Drink coffee
+
+# In the evening
+
+## Dinner
+
+- Eat spaghetti
+- Drink wine
+
+## Going to sleep
+
+- Get in bed
+- Count sheep
\ No newline at end of file
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-website/.gitignore b/tests/docs/playwright/connect-deploy-tests/connect-website/.gitignore
new file mode 100644
index 0000000000..075b2542af
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-website/.gitignore
@@ -0,0 +1 @@
+/.quarto/
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-website/_quarto.yml b/tests/docs/playwright/connect-deploy-tests/connect-website/_quarto.yml
new file mode 100644
index 0000000000..39c14b58e9
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-website/_quarto.yml
@@ -0,0 +1,19 @@
+project:
+ type: website
+
+website:
+ title: "website"
+ navbar:
+ left:
+ - href: index.qmd
+ text: Home
+ - about.qmd
+
+format:
+ html:
+ theme: cosmo
+ css: styles.css
+ toc: true
+
+
+
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-website/about.qmd b/tests/docs/playwright/connect-deploy-tests/connect-website/about.qmd
new file mode 100644
index 0000000000..07c5e7f9d1
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-website/about.qmd
@@ -0,0 +1,5 @@
+---
+title: "About"
+---
+
+About this site
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-website/index.qmd b/tests/docs/playwright/connect-deploy-tests/connect-website/index.qmd
new file mode 100644
index 0000000000..2936cbb6a0
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-website/index.qmd
@@ -0,0 +1,7 @@
+---
+title: "website"
+---
+
+This is a Quarto website.
+
+To learn more about Quarto websites visit .
diff --git a/tests/docs/playwright/connect-deploy-tests/connect-website/styles.css b/tests/docs/playwright/connect-deploy-tests/connect-website/styles.css
new file mode 100644
index 0000000000..2ddf50c7b4
--- /dev/null
+++ b/tests/docs/playwright/connect-deploy-tests/connect-website/styles.css
@@ -0,0 +1 @@
+/* css styles */
diff --git a/tests/integration/playwright/connect-integration-tests/manuscript_deploy.spec.ts b/tests/integration/playwright/connect-integration-tests/manuscript_deploy.spec.ts
new file mode 100644
index 0000000000..39a1b688b4
--- /dev/null
+++ b/tests/integration/playwright/connect-integration-tests/manuscript_deploy.spec.ts
@@ -0,0 +1,17 @@
+import { test, expect } from "@playwright/test";
+import { deployQuartoDocument, renderQuartoDocument } from "./utils";
+
+test("Verify deploying Quarto manuscript to Connect works as expected", async ({ page }) => {
+ const title = "quarto-manuscript-test";
+ const quartoDocPath = "/Users/karangathani/Documents/GitHub/quarto-cli/tests/docs/playwright/connect-deploy-tests/connect-manuscript/";
+
+ const renderDoc = await renderQuartoDocument(quartoDocPath);
+ const url = await deployQuartoDocument(title, quartoDocPath);
+
+ await page.goto(url);
+ await expect(page).toHaveTitle("manuscript");
+ await expect(page.locator('h1')).toContainText('manuscript');
+ await page.getByRole('heading', { name: 'Table of contents' }).click();
+ await expect(page.locator('#section')).toContainText('Section');
+ await expect(page.locator('#references')).toContainText('References');
+});
diff --git a/tests/integration/playwright/connect-integration-tests/presentation_deploy.spec.ts b/tests/integration/playwright/connect-integration-tests/presentation_deploy.spec.ts
new file mode 100644
index 0000000000..239c097963
--- /dev/null
+++ b/tests/integration/playwright/connect-integration-tests/presentation_deploy.spec.ts
@@ -0,0 +1,15 @@
+import { test, expect } from "@playwright/test";
+import { deployQuartoDocument, renderQuartoDocument } from "./utils"
+
+test("Verify deploying Quarto presentation to Connect works as expected", async ({ page }) => {
+ const title = "quarto-presentation-test";
+ const quartoDocPath = "/Users/karangathani/Documents/GitHub/quarto-cli/tests/docs/playwright/connect-deploy-tests/connect-presentation/";
+
+ const renderDoc = await renderQuartoDocument(quartoDocPath);
+ const url = await deployQuartoDocument(title, `${quartoDocPath}*.qmd`);
+
+ await page.goto(url);
+ await expect(page).toHaveTitle("Habits");
+ await expect(page.getByRole("heading")).toContainText("Habits");
+ await expect(page.locator("#title-slide")).toContainText("Jane Doe");
+});
diff --git a/tests/integration/playwright/connect-integration-tests/utils.ts b/tests/integration/playwright/connect-integration-tests/utils.ts
new file mode 100644
index 0000000000..339e70f99d
--- /dev/null
+++ b/tests/integration/playwright/connect-integration-tests/utils.ts
@@ -0,0 +1,50 @@
+export async function deployQuartoDocument(
+ title: string,
+ quartoDocPath: string
+): Promise {
+ let serverUrl = process.env.DEPLOY_CONNECT_SERVER_URL;
+ let apiKey = process.env.DEPLOY_CONNECT_SERVER_API_KEY;
+
+ // check for the existing app on connect server
+ let rsconnectSearchCommand = await import("child_process").then(cp => cp.execSync(
+ `rsconnect content search -s ${serverUrl} -k ${apiKey} --title-contains ${title}`
+ ));
+ let appId = JSON.parse(rsconnectSearchCommand.toString())[0]["id"];
+ let guid = JSON.parse(rsconnectSearchCommand.toString())[0]["guid"];
+ // Deploy the quarto document to Connect server
+ let rsconnectDeployCommand = await import("child_process").then(cp => cp.execSync(
+ `rsconnect deploy quarto ${quartoDocPath} -s ${serverUrl} -k ${apiKey} --app-id ${appId}`
+ ));
+ console.log(rsconnectDeployCommand.toString());
+ const connectAppUrl = `${serverUrl}/__api__/v1/content/${guid}`;
+ const payload = '{"access_type":"all"}';
+ const headers = {
+ Authorization: `Key ${apiKey}`,
+ Accept: "application/json",
+ };
+ // Change the permissions to all users in order for tests to visit the quarto url on connect
+ const response = await fetch(connectAppUrl, {
+ method: "PATCH",
+ headers: headers,
+ body: payload,
+ });
+
+ if (response.status !== 200) {
+ throw new Error(`Request failed with status ${response.status}`);
+ }
+
+ return `${serverUrl}/content/${guid}`;
+}
+
+export async function renderQuartoDocument(quartoDocPath: string): Promise {
+ let quartoRenderCommand = await import("child_process").then(cp => cp.execSync(
+ `quarto render ${quartoDocPath}/*.qmd`
+ ));
+
+ // check in the quartoRenderCommand if "Output created:" is present
+ if (quartoRenderCommand.toString().includes("Output created:")) {
+ console.log("Output created");
+ } else {
+ console.log("Output not created");
+ }
+}
diff --git a/tests/integration/playwright/connect-integration-tests/website_deploy.spec.ts b/tests/integration/playwright/connect-integration-tests/website_deploy.spec.ts
new file mode 100644
index 0000000000..03d953e2fb
--- /dev/null
+++ b/tests/integration/playwright/connect-integration-tests/website_deploy.spec.ts
@@ -0,0 +1,17 @@
+import { test, expect } from "@playwright/test";
+import { deployQuartoDocument, renderQuartoDocument } from "./utils"
+
+test("Verify deploying Quarto website to Connect works as expected", async ({ page }) => {
+ const title = "quarto-website-test";
+ const quartoDocPath = "/Users/karangathani/Documents/GitHub/quarto-cli/tests/docs/playwright/connect-deploy-tests/connect-website/";
+
+ const renderDoc = await renderQuartoDocument(quartoDocPath);
+ const url = await deployQuartoDocument(title, quartoDocPath);
+
+ await page.goto(url);
+ await expect(page).toHaveTitle("website");
+ await expect(page.getByRole('heading')).toContainText('website');
+ await expect(page.locator('#quarto-document-content')).toContainText('This is a Quarto website.');
+ await page.getByRole('link', { name: 'About' }).click();
+ await expect(page.getByRole('paragraph')).toContainText('About this site');
+});