diff --git a/acrobat/blocks/acom-widget/acom-widget.css b/acrobat/blocks/acom-widget/acom-widget.css
index 3c609997..d8d951c5 100644
--- a/acrobat/blocks/acom-widget/acom-widget.css
+++ b/acrobat/blocks/acom-widget/acom-widget.css
@@ -5,61 +5,29 @@
min-height: 623px;
}
-.demo-text {
- text-align: center;
- font-size: 8px;
- margin: 0;
- background: #7396ff;
-}
-
.acom-widget.ready {
color: initial;
}
-.widget-sub {
- margin: 0;
- text-align: left;
- display: flex;
- align-items: center;
- max-width: 300px;
- padding: 40px 0 0 40px;
- font-size: 22px;
- font-weight: 600;
- line-height: 28px;
-}
-
-.widget-center {
- border: 3px #e1e1e1 dashed;
- width: calc(100% - 48px);
- margin: auto;
- height: 70%;
- border-radius: 8px;
-}
-
-.widget-center.dragging {
- border: 3px #7396ff solid;
-}
-
-.widget-legal {
+.acom-legal {
margin-top: 30px;
font-size: 14px;
line-height: 20px;
max-width: 527px;
text-align: left;
display: inline-block;
-
+ color: #2c2c2c;
}
-.widget-icon {
- width: 20px;
- height: 20px;
+.acom-icon {
+ height: 56px;
+ min-width: 56px;
background-image: url('../../img/icons/widget-icon.png');
background-size: cover;
- display: inline-block;
- margin-right: 10px;
+ display: inline-flex;
}
-.widget-big-icon {
+.acom-big-icon {
width: 500px;
height: 500px;
background-image: url('../../img/icons/chat-pdf.svg');
@@ -82,9 +50,7 @@
display: inline-block;
}
-.widget-footer {
- padding-top: 24px;
- margin-top: 70px;
+.acom-footer {
text-align: center;
}
@@ -105,88 +71,127 @@
transition: visibility 0s, opacity 0.5s linear;
}
-.status-bar {
- margin-left: 40px;
- font-size: 16px;
- color: #464646;
- display: inline-flex;
- max-width: 550px;
- justify-content: space-between;
-}
-.status-bar.hide {
- display: none;
+
+/* new css */
+
+.acom-widget {
+ padding: 19px;
}
-.pBar-wrapper {
- height: 8px;
- width: 550px;
- background: #d5d5d5;
- margin-left: 40px;
- margin-top: 20px;
- border-radius: 25px;
+.acom-wrapper {
+ width: 75%;
+ max-width: 75%;
+ margin-left: auto;
+ margin-right: auto;
+ display: flex;
+ flex: 1 1 auto;
+ flex-direction: column;
+ justify-content: center;
+ border-radius: 20px;
+ border: 3px dashed #d5d5d5;
+ position: relative;
+ background-color: #fff;
+ min-height: 560px;
}
+.acom-wrapper.dragging {
+ background-color: #ecf5ff;
+ border: 3px #0265dc solid;
+}
-.pBar {
- position: relative;
- height: 8px;
- width: 0%;
- background: #6338ee;
- border-radius: 25px;
- max-width: 100% !important;
+.acom-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
}
-.widget-heading {
- font-size: 72px;
- font-weight: 600;
- line-height: 130%;
- margin: 0;
- padding: 0 0 0 40px;
- text-align: left;
+.acom-col {
+ flex: 100%;
}
-.widget-copy {
+.acom-copy {
+ text-align: left;
font-size: 22px;
font-weight: 400;
line-height: 33px;
- text-align: left;
- padding: 0 0 0 40px;
- width: 466px;
+ color: #2c2c2c;
+ margin: revert;
}
-.widget-wrapper {
- margin: 5px;
- background-color: #fff;
- min-height: 443px;
- height: 100%;
- width: 100%;
+.acom-cta {
+ background: #1473e6;
+ border-radius: 8px;
+ padding: 11px 27px;
+ color: white;
+ white-space: nowrap;
+ font-weight: 700;
display: flex;
- flex: 1 1 auto;
- flex-direction: column;
- border: 2px dashed #d5d5d5;
- border-radius: 20px;
-}
-
-.action-area {
- margin-top: 32px;
- padding: 0 40px;
+ justify-content: center;
+ align-items: center;
+ width: 30%;
}
-.widget-button {
- border-radius: 24px;
- font-size: 18px;
- font-weight: 700;
- height: 48px;
- padding: 12px 24px;
- white-space: nowrap;
- background-color: #0265dc;
- color: white;
- border-color: transparent;
+.acom-cta::before {
+ content: '';
+ background-image: url('/acrobat/img/icons/upload-icon.svg');
+ background-repeat: no-repeat;
+ background-size: 32px 28px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 8px;
+ width: 32px;
+ height: 28px;
}
-.widget-button:hover {
+.acom-cta:hover {
text-decoration: none;
color: #fff;
background: #0054b6;
}
+
+.acom-error {
+ background: #d8120b;
+ width: fit-content;
+ border-radius: 8px;
+ padding: 11px 27px;
+ color: white;
+ white-space: nowrap;
+ font-weight: 700;
+ display: flex;
+}
+
+.acom-heading {
+ color: #2c2c2c;
+ text-align: left;
+ font-weight: 600;
+ font-size: 44px;
+ margin: revert;
+ margin-bottom: 16px;
+}
+
+.acom-header {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ margin-bottom: 24px;
+}
+
+.acom-title {
+ font-size: 30px;
+ font-weight: bold;
+ color: black;
+ margin-left: 15px;
+}
+
+@media screen and (min-width: 768px) {
+ .acom-container {
+ align-items: center;
+ display: flex;
+ flex: 1 1 55%;
+ flex-direction: row;
+ padding: 48px 0 48px 48px;
+ }
+
+}
diff --git a/acrobat/blocks/acom-widget/acom-widget.js b/acrobat/blocks/acom-widget/acom-widget.js
index aa58e588..21985d75 100644
--- a/acrobat/blocks/acom-widget/acom-widget.js
+++ b/acrobat/blocks/acom-widget/acom-widget.js
@@ -8,182 +8,186 @@ import {
getAcrobatWebLink,
} from './pdfAssetManager.js';
+import LIMITS from './limits.js';
+
+
import { setLibs } from '../../scripts/utils.js';
const miloLibs = setLibs('/libs');
+const { createTag } = await import(`${miloLibs}/utils/utils.js`);
// eslint-disable-next-line compat/compat
const PAGE_URL = new URL(window.location.href);
const redirect = PAGE_URL.searchParams.get('redirect');
-const uploadToAdobe = async (file, progressSection) => {
- const { progressBarWrapper, progressBar } = progressSection;
- const statusBar = document.querySelector('.status-bar');
- const cancelButton = document.querySelector('.widget-cancel');
+const uploadToAdobe = async (file, verb, err) => {
const filename = file.name;
- const extension = filename.split('.').pop().toLowerCase();
let xhr;
- const contentTypes = {
- png: 'image/png',
- jpg: 'image/jpeg',
- jpeg: 'image/jpeg',
- svg: 'image/svg+xml',
- pdf: 'application/pdf',
- };
-
- const contentType = contentTypes[extension];
- if (!contentType) {
- // eslint-disable-next-line no-alert
- alert('This file is invalid');
+ // Check file type
+ if (LIMITS[verb].acceptedFiles.indexOf(file.type) < 0) {
+ err.classList.add('acom-error');
+ err.classList.remove('hide');
+ err.textContent = 'USE mph / not accepted';
+
+ setTimeout(() => {
+ err.classList.remove('acom-error');
+ err.classList.add('hide');
+ }, 3000);
return;
}
- // Progress Bar Setup
- document.querySelector('.widget-copy').classList.add('hide');
- document.querySelector('.widget-button').classList.add('hide');
- statusBar.classList.remove('hide');
- cancelButton.classList.remove('hide');
- document
- .querySelector('.action-area')
- .insertAdjacentElement('beforebegin', progressBarWrapper);
- progressBarWrapper.append(progressBar);
- progressBarWrapper.insertAdjacentElement('beforebegin', statusBar);
-
- const updateProgressBar = (event) => {
- if (event.lengthComputable) {
- const percentComplete = (event.loaded / event.total) * 100;
- progressBar.style.width = `${percentComplete}%`;
- statusBar.querySelector('.percentage').textContent = `${percentComplete.toFixed(0)}%`;
- }
- };
-
- const cancelUpload = () => {
- xhr.abort();
- document.querySelector('#file-upload').value = null;
- document.querySelector('.widget-button').classList.remove('hide');
- progressBarWrapper.classList.add('hide');
- progressBar.style.width = '0%';
- cancelButton.classList.add('hide');
- statusBar.classList.add('hide');
- document.querySelector('.widget-copy').classList.remove('hide');
- document.querySelector('.widget-button').classList.remove('hide');
- };
-
- cancelButton.addEventListener('click', cancelUpload);
-
- try {
- const { accessToken, discoveryResources } = await initializePdfAssetManager();
- const uploadEndpoint = validateSSRF(discoveryResources.assets.upload.uri);
- const formData = prepareFormData(file, filename);
-
- xhr = new XMLHttpRequest();
- xhr.open('POST', uploadEndpoint, true);
- xhr.setRequestHeader('Authorization', `Bearer ${accessToken}`);
- xhr.upload.addEventListener('progress', updateProgressBar, false);
-
- xhr.onreadystatechange = async () => {
- if (xhr.readyState === 4 && xhr.status === 201) {
- const uploadResult = JSON.parse(xhr.responseText);
- const assetUri = uploadResult.uri;
-
- if (contentType !== 'application/pdf') {
- const createPdfEndpoint = validateSSRF(discoveryResources.assets.createpdf.uri);
- const createPdfPayload = {
- asset_uri: assetUri,
- name: filename,
- persistence: 'transient',
- };
- try {
- const createPdfResult = await createPdf(
- createPdfEndpoint,
- createPdfPayload,
- accessToken,
- );
- const jobUri = createPdfResult.job_uri;
- await checkJobStatus(jobUri, accessToken, discoveryResources);
- } catch (error) {
- // eslint-disable-next-line no-alert
- alert('Failed to create PDF');
- throw new Error('Error creating PDF:', error);
- }
- }
-
- try {
- const downloadUri = await getDownloadUri(assetUri, accessToken, discoveryResources);
- const blobViewerUrl = validateSSRF(getAcrobatWebLink(filename, assetUri, downloadUri));
- if (redirect !== 'off') {
- window.location.href = blobViewerUrl;
- } else {
- // eslint-disable-next-line no-console
- console.log('Blob Viewer URL:', `View PDF `);
- }
- } catch (error) {
- throw new Error('Error getting download URI:', error);
- }
- }
- };
+ // Check file size
+ if (file.size > LIMITS[verb].maxFileSize
+ || file.size < 1) {
+ err.classList.add('acom-error');
+ err.classList.remove('hide');
+ err.textContent = `${file.size < 1 ? 'FILE IS EMPTY' : 'FILE IS TOO BIG'}`;
+
+ setTimeout(() => {
+ err.classList.remove('acom-error');
+ err.classList.add('hide');
+ }, 3000);
+ return;
+ }
+
+ // try {
+ // const { accessToken, discoveryResources } = await initializePdfAssetManager();
+ // const uploadEndpoint = validateSSRF(discoveryResources.assets.upload.uri);
+ // const formData = prepareFormData(file, filename);
+
+ // xhr = new XMLHttpRequest();
+ // xhr.open('POST', uploadEndpoint, true);
+ // xhr.setRequestHeader('Authorization', `Bearer ${accessToken}`);
+
+ // xhr.onreadystatechange = async () => {
+ // if (xhr.readyState === 4 && xhr.status === 201) {
+ // const uploadResult = JSON.parse(xhr.responseText);
+ // const assetUri = uploadResult.uri;
+
+ // if (contentType !== 'application/pdf') {
+ // const createPdfEndpoint = validateSSRF(discoveryResources.assets.createpdf.uri);
+ // const createPdfPayload = {
+ // asset_uri: assetUri,
+ // name: filename,
+ // persistence: 'transient',
+ // };
+ // try {
+ // const createPdfResult = await createPdf(
+ // createPdfEndpoint,
+ // createPdfPayload,
+ // accessToken,
+ // );
+ // const jobUri = createPdfResult.job_uri;
+ // await checkJobStatus(jobUri, accessToken, discoveryResources);
+ // } catch (error) {
+ // // eslint-disable-next-line no-alert
+ // alert('Failed to create PDF');
+ // throw new Error('Error creating PDF:', error);
+ // }
+ // }
+
+ // try {
+ // const downloadUri = await getDownloadUri(assetUri, accessToken, discoveryResources);
+ // const blobViewerUrl = validateSSRF(getAcrobatWebLink(filename, assetUri, downloadUri));
+ // if (redirect !== 'off') {
+ // window.location.href = blobViewerUrl;
+ // } else {
+ // // eslint-disable-next-line no-console
+ // console.log('Blob Viewer URL:', `View PDF `);
+ // }
+ // } catch (error) {
+ // throw new Error('Error getting download URI:', error);
+ // }
+ // }
+ // };
+
+ // xhr.send(formData);
+ // } catch (error) {
+ // // eslint-disable-next-line no-alert
+ // alert('An error occurred during the upload process. Please try again.');
+ // throw new Error('Error uploading file:', error);
+ // }
+};
- xhr.send(formData);
- } catch (error) {
- // eslint-disable-next-line no-alert
- alert('An error occurred during the upload process. Please try again.');
- throw new Error('Error uploading file:', error);
+const dropFiles = (ev, verb, errorState) => {
+ ev.preventDefault();
+ console.log(ev);
+
+ if (ev.dataTransfer.items) {
+ [...ev.dataTransfer.items].forEach((item) => {
+ // Add check for multiple files.
+ if (item.kind === 'file') {
+ const file = item.getAsFile();
+ uploadToAdobe(file, verb, errorState);
+ }
+ });
+ } else {
+ [...ev.dataTransfer.files].forEach((file, i) => {
+ // copy functionality from dataTransfer.items
+ });
}
};
-const createProgressSection = (createTag) => ({
- progressBarWrapper: createTag('div', { class: 'pBar-wrapper' }),
- progressBar: createTag('div', { class: 'pBar' }),
- cancelButton: document.querySelector('.cancel-button'),
-});
+const setDraggingClass = (widget, shouldToggle) => {
+ shouldToggle ? widget.classList.add('dragging') : widget.classList.remove('dragging');
+}
export default async function init(element) {
- const { createTag } = await import(`${miloLibs}/utils/utils.js`);
- const content = Array.from(element.querySelectorAll(':scope > div'));
- content.forEach((con) => con.classList.add('hide'));
+ const children = element.querySelectorAll(':scope > div');
+ const VERB = element.classList[1];
+ const widgetHeading = createTag('h1', { class: 'acom-heading' }, children[0].textContent);
- element.classList.add('ready');
-
- const wrapperNew = createTag('div', { id: 'CIDTWO', class: 'fsw widget-wrapper facade' });
- const wrapper = createTag('div', { id: 'CID', class: 'fsw widget-wrapper' });
- const heading = createTag('h1', { class: 'widget-heading' }, content[1].textContent);
- const copy = createTag('p', { class: 'widget-copy' }, content[2].textContent);
- const actionArea = createTag('p', { class: 'action-area' });
- const statusBar = createTag('p', { class: 'status-bar hide' });
- const statusMessage = createTag('span', { class: 'message' }, 'Uploading file to acrobat.adobe.com');
- const statusPercentage = createTag('span', { class: 'percentage' }, '0%');
+ children.forEach((child) => {
+ child.remove();
+ });
+ const widget = createTag('div', { id: 'drop-zone', class: 'acom-wrapper' });
+ const widgetContainer = createTag('div', { class: 'acom-container' });
+ const widgetRow = createTag('div', { class: 'acom-row' });
+ const widgetLeft = createTag('div', { class: 'acom-col' });
+ const widgetRight = createTag('div', { class: 'acom-col' });
+ const widgetHeader = createTag('div', { class: 'acom-header' });
+ const widgetIcon = createTag('div', { class: 'acom-icon' });
+ const widgetTitle = createTag('div', { class: 'acom-title' }, 'Acrobat');
+ const widgetCopy = createTag('p', { class: 'acom-copy' }, 'Drag and drop a PDF to use the Acrobat PDF form filler.');
+ const widgetButton = createTag('label', { for: 'file-upload', class: 'acom-cta' }, 'Select a file');
const button = createTag('input', { type: 'file', id: 'file-upload', class: 'hide' });
- const cancelButton = createTag('button', { class: 'widget-cancel con-button outline button-xl hide' }, 'Cancel');
- const buttonLabel = createTag('label', { for: 'file-upload', class: 'widget-button' }, content[3].textContent);
- const legal = createTag('p', { class: 'widget-legal' }, content[4].textContent);
- const subTitle = createTag('p', { class: 'widget-sub' }, 'Adobe Acrobat');
- const iconLogo = createTag('div', { class: 'widget-icon' });
+ const errorState = createTag('div', { class: 'hide' });
+ const widgetImage = createTag('img', { class: 'acom-image', src: children[1].querySelector('img')?.src });
+
+ const legal = createTag('p', { class: 'acom-legal' }, 'Your file will be securely handled by Adobe servers and deleted unless you sign in to save it. By using this service, you agree to the Adobe Terms of Use and Privacy Policy.');
const iconSecurity = createTag('div', { class: 'security-icon' });
- const icon = createTag('div', { class: 'widget-big-icon' });
- const footer = createTag('div', { class: 'widget-footer' });
-
- wrapper.append(subTitle);
- subTitle.prepend(iconLogo);
- wrapper.append(icon, heading, copy, statusBar);
- statusBar.append(statusMessage, statusPercentage);
- actionArea.append(button, cancelButton, buttonLabel);
- wrapper.append(actionArea);
+ const footer = createTag('div', { class: 'acom-footer' });
footer.append(iconSecurity, legal);
- element.append(wrapper, footer, wrapperNew);
- if (Number(window.localStorage.limit) > 1) {
- const upsell = createTag('div', { class: 'upsell' }, 'You have reached your limit. Please upgrade.');
- wrapper.append(upsell);
- element.append(wrapper);
- }
+ widget.append(widgetContainer);
+ widgetContainer.append(widgetRow);
+ widgetRight.append(widgetImage);
+ widgetRow.append(widgetLeft, widgetRight);
+ widgetHeader.append(widgetIcon, widgetTitle);
+ widgetLeft.append(widgetHeader, widgetHeading, widgetCopy, errorState, widgetButton, button);
+
+ element.append(widget, footer);
button.addEventListener('change', (e) => {
const file = e.target.files[0];
- const progressSection = createProgressSection(createTag);
if (file) {
- uploadToAdobe(file, progressSection);
+ uploadToAdobe(file, VERB, errorState);
}
});
+
+ widget.addEventListener('dragover', (e) => {
+ e.preventDefault();
+ setDraggingClass(widget, true);
+ });
+
+ widget.addEventListener('dragleave', (file) => {
+ setDraggingClass(widget, false);
+ });
+
+ widget.addEventListener('drop', (e) => {
+ dropFiles(e, VERB, errorState);
+ setDraggingClass(widget, false);
+ });
}
diff --git a/acrobat/blocks/acom-widget/limits.js b/acrobat/blocks/acom-widget/limits.js
new file mode 100644
index 00000000..d828239a
--- /dev/null
+++ b/acrobat/blocks/acom-widget/limits.js
@@ -0,0 +1,24 @@
+const LIMITS = {
+ fillsign: {
+ maxFileSize: 100000000, // 1 MB
+ acceptedFiles: ['application/pdf'],
+ maxNumFiles: 1,
+ },
+ 'delete-pages': {
+ maxFileSize: 100000000, // 1 MB
+ acceptedFiles: ['application/pdf'],
+ maxNumFiles: 1,
+ },
+ 'number-pages': {
+ maxFileSize: 100000000, // 1 MB
+ acceptedFiles: ['application/pdf'],
+ maxNumFiles: 1,
+ },
+ 'compress-pdf': {
+ maxFileSize: 100000000,
+ acceptedFiles: ['application/pdf'],
+ maxNumFiles: 1,
+ },
+};
+
+export default LIMITS;
diff --git a/acrobat/blocks/dc-converter-widget/dc-converter-widget.js b/acrobat/blocks/dc-converter-widget/dc-converter-widget.js
index c41a9f4a..95f32b77 100644
--- a/acrobat/blocks/dc-converter-widget/dc-converter-widget.js
+++ b/acrobat/blocks/dc-converter-widget/dc-converter-widget.js
@@ -284,7 +284,7 @@ export default async function init(element) {
if (preRenderDropZone) {
dcScript.dataset.pre_rendered = 'true'; // TODO: remove this line
}
- if (IMS_GUEST) {
+ if (IMS_GUEST && !isRedirection) {
dcScript.dataset.ims_guests = 'true';
}
@@ -324,16 +324,20 @@ export default async function init(element) {
ocrPDF: canNotUpload || (val.ocr_pdf && !val.ocr_pdf.can_process),
};
window.doccloudPersonalization = doccloudPersonalization;
+
+ const downloadStatus = doccloudPersonalization.download?.can_download ? 'can_download' : 'cannot_download';
+ localStorage.setItem('frictionless.download', downloadStatus);
// Personalization Ready Event
const personalizationIsReady = new CustomEvent('Personalization:Ready');
window.dispatchEvent(personalizationIsReady);
- }).catch(() => {
- window.dispatchEvent(new CustomEvent('DC_Hosted:Error'));
+ }).catch((err) => {
+ const detail = JSON.stringify(err, Object.getOwnPropertyNames(err));
+ window.dispatchEvent(new CustomEvent('DC_Hosted:Error', { detail }));
});
});
- window.addEventListener('DC_Hosted:Error', () => {
+ window.addEventListener('DC_Hosted:Error', (err) => {
const dropZone = document.querySelector('.dropZoneContent');
if (dropZone && !dropZone.classList.contains('unavailable')) {
dropZone.classList.add('unavailable');
@@ -343,6 +347,6 @@ export default async function init(element) {
dropZone.innerHTML = '
We apologize for the inconvenience. We are working hard to make the service available. Please check back shortly.
';
document.querySelector('div[class*="DropZoneFooter__dropzoneFooter"]').innerHTML = '';
}
- window.lana?.log('DC Widget failed', lanaOptions);
+ window.lana?.log(`DC Widget failed. detail: ${JSON.stringify(err.detail)}`, lanaOptions);
});
}
diff --git a/acrobat/img/icons/upload-icon.svg b/acrobat/img/icons/upload-icon.svg
new file mode 100644
index 00000000..ff1d8e4f
--- /dev/null
+++ b/acrobat/img/icons/upload-icon.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/acrobat/scripts/alloy/mobile-widget-shown.js b/acrobat/scripts/alloy/mobile-widget-shown.js
index b2897e63..d2b37eef 100644
--- a/acrobat/scripts/alloy/mobile-widget-shown.js
+++ b/acrobat/scripts/alloy/mobile-widget-shown.js
@@ -1,6 +1,8 @@
-const params = new Proxy(new URLSearchParams(window.location.search),{
- get: (searchParams, prop) => searchParams.get(prop),
-});
+const params = new Proxy(
+ // eslint-disable-next-line compat/compat
+ new URLSearchParams(window.location.search),
+ { get: (searchParams, prop) => searchParams.get(prop) },
+);
let appReferrer = params.x_api_client_id || params['x-product'] || '';
if (params.x_api_client_location || params['x-product-location']) {
@@ -53,6 +55,7 @@ export default function init(verb) {
is_authenticated: false,
user_tags: [
`${localStorage['pdfnow.auth'] ? 'frictionless_return_user' : 'frictionless_new_user'}`,
+ `${localStorage['frictionless.download'] === 'cannot_download' ? 'frictionless_cannot_download' : 'frictionless_can_download'}`,
],
},
},
@@ -62,8 +65,10 @@ export default function init(verb) {
};
// Alloy Ready...
const AlloyReady = setInterval(() => {
+ // eslint-disable-next-line no-underscore-dangle
if (window?._satellite?.track) {
clearInterval(AlloyReady);
+ // eslint-disable-next-line no-underscore-dangle
window?._satellite?.track('event', event);
}
}, 1000);
diff --git a/acrobat/scripts/alloy/mobile-widget.js b/acrobat/scripts/alloy/mobile-widget.js
index 4df0cef0..2894874a 100644
--- a/acrobat/scripts/alloy/mobile-widget.js
+++ b/acrobat/scripts/alloy/mobile-widget.js
@@ -1,6 +1,8 @@
-const params = new Proxy(new URLSearchParams(window.location.search),{
- get: (searchParams, prop) => searchParams.get(prop),
-});
+const params = new Proxy(
+ // eslint-disable-next-line compat/compat
+ new URLSearchParams(window.location.search),
+ { get: (searchParams, prop) => searchParams.get(prop) },
+);
let appReferrer = params.x_api_client_id || params['x-product'] || '';
if (params.x_api_client_location || params['x-product-location']) {
@@ -53,6 +55,7 @@ export default function init(verb) {
is_authenticated: false,
user_tags: [
`${localStorage['pdfnow.auth'] ? 'frictionless_return_user' : 'frictionless_new_user'}`,
+ `${localStorage['frictionless.download'] === 'cannot_download' ? 'frictionless_cannot_download' : 'frictionless_can_download'}`,
],
},
},
@@ -60,5 +63,6 @@ export default function init(verb) {
},
},
};
+ // eslint-disable-next-line no-underscore-dangle
window?._satellite?.track('event', event);
}
diff --git a/acrobat/scripts/scripts.js b/acrobat/scripts/scripts.js
index ef7ef3f0..3754edd6 100644
--- a/acrobat/scripts/scripts.js
+++ b/acrobat/scripts/scripts.js
@@ -465,8 +465,9 @@ const { ietf } = getLocale(locales);
loadIms().then(() => {
const imsIsReady = new CustomEvent('IMS:Ready');
window.dispatchEvent(imsIsReady);
- }).catch(() => {
- window.dispatchEvent(new CustomEvent('DC_Hosted:Error'));
+ }).catch((err) => {
+ const detail = JSON.stringify(err, Object.getOwnPropertyNames(err));
+ window.dispatchEvent(new CustomEvent('DC_Hosted:Error', { detail }));
});
loadLana({ clientId: 'dxdc', tags: 'DC_Milo' });
diff --git a/edgeworkers/Acrobat_DC_web_prod/main.js b/edgeworkers/Acrobat_DC_web_prod/main.js
index eafdbfbf..54087784 100644
--- a/edgeworkers/Acrobat_DC_web_prod/main.js
+++ b/edgeworkers/Acrobat_DC_web_prod/main.js
@@ -173,15 +173,17 @@ export async function responseProvider(request) {
const csp = contentSecurityPolicy(isProd, scriptHashes);
const acrobat = isProd ? 'https://acrobat.adobe.com' : 'https://stage.acrobat.adobe.com';
const pdfnow = isProd ? 'https://pdfnow.adobe.io' : 'https://pdfnow-stage.adobe.io';
+ const adobeid = isProd ? 'https://adobeid-na1.services.adobe.com' : 'https://adobeid-na1-stg1.services.adobe.com';
const headers = {
...responseHeaders,
'Content-Security-Policy': csp,
Link: [
`<${acrobat}>;rel="preconnect"`,
- ';rel="preconnect"',
+ `<${adobeid}>;rel="preconnect"`,
`<${pdfnow}>;rel="preconnect"`,
';rel="preconnect"',
';rel="preconnect"',
+ `;rel="preload";as="script"`,
`<${acrobat}/dc-core/${dcCoreVersion}/dc-core.js>;rel="preload";as="script"`,
`<${acrobat}/dc-core/${dcCoreVersion}/dc-core.css>;rel="preload";as="style"`,
].join()
diff --git a/package-lock.json b/package-lock.json
index 0881b5b7..929bcedd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"dependencies": {
"@75lb/deep-merge": "^1.1.2",
"@rollup/plugin-replace": "5.0.5",
+ "@testing-library/user-event": "^14.5.2",
"@web/dev-server-rollup": "0.6.1",
"@web/test-runner": "0.18.1",
"@web/test-runner-commands": "0.9.0",
@@ -1927,7 +1928,6 @@
"version": "7.23.1",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz",
"integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==",
- "dev": true,
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -3783,6 +3783,109 @@
"node": ">=14"
}
},
+ "node_modules/@testing-library/dom": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
+ "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
+ "peer": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/runtime": "^7.12.5",
+ "@types/aria-query": "^5.0.1",
+ "aria-query": "5.3.0",
+ "chalk": "^4.1.0",
+ "dom-accessibility-api": "^0.5.9",
+ "lz-string": "^1.5.0",
+ "pretty-format": "^27.0.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@testing-library/dom/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@testing-library/dom/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "peer": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/@testing-library/dom/node_modules/chalk/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "peer": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@testing-library/dom/node_modules/pretty-format": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
+ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
+ "peer": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^17.0.1"
+ },
+ "engines": {
+ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+ }
+ },
+ "node_modules/@testing-library/dom/node_modules/react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
+ "peer": true
+ },
+ "node_modules/@testing-library/dom/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "peer": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@testing-library/user-event": {
+ "version": "14.5.2",
+ "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz",
+ "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==",
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ },
+ "peerDependencies": {
+ "@testing-library/dom": ">=7.21.4"
+ }
+ },
"node_modules/@tootallnate/once": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@@ -3814,6 +3917,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/aria-query": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
+ "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
+ "peer": true
+ },
"node_modules/@types/babel__code-frame": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/@types/babel__code-frame/-/babel__code-frame-7.0.4.tgz",
@@ -4631,7 +4740,6 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true,
"engines": {
"node": ">=10"
},
@@ -4663,6 +4771,15 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
+ "node_modules/aria-query": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
+ "peer": true,
+ "dependencies": {
+ "dequal": "^2.0.3"
+ }
+ },
"node_modules/array-back": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz",
@@ -6578,6 +6695,15 @@
"node": ">= 0.6.0"
}
},
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "peer": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
@@ -6641,6 +6767,12 @@
"node": ">=6.0.0"
}
},
+ "node_modules/dom-accessibility-api": {
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
+ "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
+ "peer": true
+ },
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
@@ -11269,6 +11401,15 @@
"node": ">=12"
}
},
+ "node_modules/lz-string": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
+ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
+ "peer": true,
+ "bin": {
+ "lz-string": "bin/bin.js"
+ }
+ },
"node_modules/magic-string": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
@@ -13736,8 +13877,7 @@
"node_modules/regenerator-runtime": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
- "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==",
- "dev": true
+ "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
},
"node_modules/regenerator-transform": {
"version": "0.15.2",
diff --git a/package.json b/package.json
index c0e4fab4..3b3bd3c9 100644
--- a/package.json
+++ b/package.json
@@ -6,13 +6,17 @@
"scripts": {
"test": "npm run wtr && npm run jest",
"wtr": "wtr \"./test/**/*.test.(js|html)\" --node-resolve --port=2000 --coverage --concurrent-browsers 4",
+ "wtr:file": "wtr --node-resolve --port=2000 --coverage --concurrent-browsers 4",
"wtr:watch": "npm run wtr -- --watch",
+ "wtr:file:watch": "npm run wtr:file -- --watch",
"int": "wtr \"./test/integration/**/*.int.(js|html)\" --node-resolve --port=2000 --concurrent-browsers 3 --config wtr-integration.config.mjs",
"int:watch": "npm run int -- --watch",
"int3": "wtr \"./test/integration/**/*.int.(js|html)\" --node-resolve --port=2000 --concurrent-browsers 3 --config wtr-int-browsers.config.mjs",
"int3:watch": "npm run int3 -- --watch",
"jest": "jest --testPathPattern=test --coverage --coverageDirectory=coverage/jest",
+ "jest:file": "jest --coverage --coverageDirectory=coverage/jest",
"jest:watch": "npm run jest -- --watchAll",
+ "jest:file:watch": "npm run jest:file -- --watchAll",
"lcov": "lcov -a coverage/jest/lcov.info -a coverage/wtr/lcov.info -o coverage/lcov.info",
"lint": "npm run lint:js && npm run lint:css",
"lint:js": "eslint .",
@@ -63,6 +67,7 @@
"dependencies": {
"@75lb/deep-merge": "^1.1.2",
"@rollup/plugin-replace": "5.0.5",
+ "@testing-library/user-event": "^14.5.2",
"@web/dev-server-rollup": "0.6.1",
"@web/test-runner": "0.18.1",
"@web/test-runner-commands": "0.9.0",
diff --git a/test/blocks/acom-widget/acom-widget-redirect.jest.js b/test/blocks/acom-widget/acom-widget-redirect.jest.js
new file mode 100644
index 00000000..a55fd88a
--- /dev/null
+++ b/test/blocks/acom-widget/acom-widget-redirect.jest.js
@@ -0,0 +1,72 @@
+/**
+ * @jest-environment jsdom
+ */
+/* eslint-disable compat/compat */
+/* eslint-disable no-undef */
+import path from 'path';
+import fs from 'fs';
+import { userEvent } from '@testing-library/user-event';
+
+const mockFetch = jest.fn(() => Promise.resolve({
+ json: () => Promise.resolve({
+ access_token: '123',
+ discovery: {
+ resources: {
+ jobs: { status: { uri: 'https://pdfnow-dev.adobe.io/status' } },
+ assets: {
+ upload: { uri: 'https://pdfnow-dev.adobe.io/upload' },
+ download_uri: { uri: 'https://pdfnow-dev.adobe.io/download' },
+ createpdf: { uri: 'https://pdfnow-dev.adobe.io/createpdf' },
+ },
+ },
+ },
+ }),
+ ok: true,
+}));
+
+const xhrMock = {
+ abort: jest.fn(),
+ open: jest.fn(),
+ setRequestHeader: jest.fn(),
+ onreadystatechange: jest.fn(),
+ progress: jest.fn(),
+ upload: new EventTarget(),
+ send: jest.fn(),
+ readyState: 4,
+ responseText: JSON.stringify({
+ uri: 'https://www.example.com',
+ job_uri: 'https://www.example.com/job_uri',
+ }),
+ status: 201,
+};
+
+describe('acom-widget block', () => {
+ beforeEach(() => {
+ document.head.innerHTML = fs.readFileSync(path.resolve(__dirname, './mocks/head.html'), 'utf8');
+ document.body.innerHTML = fs.readFileSync(path.resolve(__dirname, './mocks/body.html'), 'utf8');
+ window.fetch = mockFetch;
+ window.XMLHttpRequest = jest.fn(() => xhrMock);
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('upload PDF', async () => {
+ const log = jest.spyOn(console, 'log');
+
+ delete window.location;
+ window.location = new URL('https://localhost/acrobat/online/ai-chat-pdf.html?redirect=off');
+
+ const blockModule = await import('../../../acrobat/blocks/acom-widget/acom-widget.js');
+
+ const block = document.querySelector('.acom-widget');
+ await blockModule.default(block);
+
+ const input = document.querySelector('input');
+ const file = new File(['hello'], 'hello.png', { type: 'image/png' });
+ await userEvent.upload(input, file);
+ await xhrMock.onreadystatechange();
+ expect(log.mock.calls[0][0]).toContain('Blob Viewer URL:');
+ });
+});
diff --git a/test/blocks/acom-widget/acom-widget.jest.js b/test/blocks/acom-widget/acom-widget.jest.js
new file mode 100644
index 00000000..46fb14a6
--- /dev/null
+++ b/test/blocks/acom-widget/acom-widget.jest.js
@@ -0,0 +1,81 @@
+/**
+ * @jest-environment jsdom
+ */
+/* eslint-disable compat/compat */
+/* eslint-disable no-undef */
+import path from 'path';
+import fs from 'fs';
+import { userEvent } from '@testing-library/user-event';
+import { delay } from '../../helpers/waitfor.js';
+import init from '../../../acrobat/blocks/acom-widget/acom-widget.js';
+
+const mockfetch = jest.fn(() => Promise.resolve({
+ json: () => Promise.resolve({
+ access_token: '123',
+ discovery: {
+ resources: {
+ jobs: { status: { uri: 'https://pdfnow-dev.adobe.io/status' } },
+ assets: {
+ upload: { uri: 'https://pdfnow-dev.adobe.io/upload' },
+ download_uri: { uri: 'https://pdfnow-dev.adobe.io/download' },
+ createpdf: { uri: 'https://pdfnow-dev.adobe.io/createpdf' },
+ },
+ },
+ },
+ }),
+ ok: true,
+}));
+
+const mockXhr = {
+ abort: jest.fn(),
+ open: jest.fn(),
+ setRequestHeader: jest.fn(),
+ onreadystatechange: jest.fn(),
+ progress: jest.fn(),
+ upload: new EventTarget(),
+ send: jest.fn(),
+ readyState: 4,
+ responseText: JSON.stringify({
+ uri: 'https://www.example.com/asseturi/',
+ job_uri: 'https://www.example.com/job_uri',
+ }),
+ status: 201,
+};
+
+describe('acom-widget block', () => {
+ beforeEach(() => {
+ document.head.innerHTML = fs.readFileSync(path.resolve(__dirname, './mocks/head.html'), 'utf8');
+ document.body.innerHTML = fs.readFileSync(path.resolve(__dirname, './mocks/body.html'), 'utf8');
+ window.fetch = mockfetch;
+ window.XMLHttpRequest = jest.fn(() => mockXhr);
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('upload PDF', async () => {
+ window.alert = jest.fn();
+
+ delete window.localStorage.limit;
+
+ delete window.location;
+ window.location = new URL('https://localhost/acrobat/online/ai-chat-pdf.html');
+
+ const block = document.querySelector('.acom-widget');
+ await init(block);
+
+ const input = document.querySelector('input');
+ const file = new File(['hello'], 'hello.png', { type: 'image/png' });
+
+ window.location = { assign: jest.fn() };
+
+ await userEvent.upload(input, file);
+
+ await mockXhr.onreadystatechange();
+
+ await delay(100);
+
+ expect(window.location.href).toMatch(/pdfNowAssetUri=https:\/\/www.example.com\/asseturi\//);
+ });
+});
diff --git a/test/blocks/acom-widget/acom-widget.test.js b/test/blocks/acom-widget/acom-widget.test.js
new file mode 100644
index 00000000..4a6be132
--- /dev/null
+++ b/test/blocks/acom-widget/acom-widget.test.js
@@ -0,0 +1,153 @@
+/* eslint-disable compat/compat */
+import { readFile } from '@web/test-runner-commands';
+import { expect } from '@esm-bundle/chai';
+import sinon from 'sinon';
+import { delay, waitForElement } from '../../helpers/waitfor.js';
+
+const { default: init } = await import(
+ '../../../acrobat/blocks/acom-widget/acom-widget.js'
+);
+
+const uploadFile = (input, file) => {
+ const changeEvent = new Event('change');
+ Object.defineProperty(changeEvent, 'target', { writable: false, value: { files: [file] } });
+ input.dispatchEvent(changeEvent);
+};
+
+describe('acom-widget block', () => {
+ let xhr;
+
+ beforeEach(async () => {
+ sinon.stub(window, 'fetch');
+ window.fetch.callsFake((x) => {
+ if (x === 'https://pdfnow-dev.adobe.io/status') {
+ return Promise.resolve({ ok: false });
+ }
+ return Promise.resolve({
+ json: () => Promise.resolve({
+ access_token: '123',
+ discovery: {
+ resources: {
+ jobs: { status: { uri: 'https://pdfnow-dev.adobe.io/status' } },
+ assets: {
+ upload: { uri: 'https://pdfnow-dev.adobe.io/upload' },
+ download_uri: { uri: 'https://pdfnow-dev.adobe.io/download' },
+ createpdf: { uri: 'https://pdfnow-dev.adobe.io/createpdf' },
+ },
+ },
+ },
+ }),
+ ok: true,
+ });
+ });
+ xhr = sinon.useFakeXMLHttpRequest();
+ document.head.innerHTML = await readFile({ path: './mocks/head.html' });
+ document.body.innerHTML = await readFile({ path: './mocks/body.html' });
+ delete window.localStorage.limit;
+ });
+
+ afterEach(() => {
+ xhr.restore();
+ sinon.restore();
+ });
+
+ it('reach limit', async () => {
+ window.localStorage.limit = 2;
+
+ const block = document.body.querySelector('.acom-widget');
+ await init(block);
+
+ expect(document.querySelector('.upsell')).to.exist;
+ });
+
+ it('upload invalid file', async () => {
+ const alert = sinon.stub(window, 'alert').callsFake(() => {});
+
+ const block = document.querySelector('.acom-widget');
+ await init(block);
+
+ const input = document.querySelector('input');
+ const file = new File(['hello'], 'hello.txt', { type: 'text/plain' });
+
+ uploadFile(input, file);
+
+ expect(alert.getCall(0).args[0]).to.eq('This file is invalid');
+ });
+
+ it('cancel upload', async () => {
+ sinon.stub(window, 'alert').callsFake(() => {});
+
+ const block = document.querySelector('.acom-widget');
+ await init(block);
+
+ const input = document.querySelector('input');
+ const file = new File(['hello'], 'hello.png', { type: 'image/png' });
+
+ uploadFile(input, file);
+
+ await delay(1000);
+
+ document.querySelector('.widget-cancel').click();
+
+ const upload = await waitForElement('#file-upload');
+ expect(upload).to.be.exist;
+ });
+
+ it('SSRF check', async () => {
+ window.fetch.restore();
+ sinon.stub(window, 'fetch');
+ window.fetch.returns(Promise.resolve({
+ json: () => Promise.resolve({
+ access_token: '123',
+ discovery: { resources: { assets: { upload: { uri: 'https://example.com/upload' } } } },
+ }),
+ ok: true,
+ }));
+ sinon.stub(window, 'alert').callsFake(() => {});
+
+ const block = document.querySelector('.acom-widget');
+ await init(block);
+
+ const input = document.querySelector('input');
+ const file = new File(['hello'], 'hello.png', { type: 'image/png' });
+
+ uploadFile(input, file);
+
+ await delay(500);
+
+ expect(alert.getCall(0).args[0]).to.eq('An error occurred during the upload process. Please try again.');
+ });
+
+ it('upload PNG and fail at job status', async () => {
+ sinon.stub(window, 'alert').callsFake(() => {});
+
+ const requests = [];
+
+ xhr.onCreate = (x) => {
+ requests.push(x);
+ };
+
+ const block = document.body.querySelector('.acom-widget');
+ await init(block);
+
+ const input = document.querySelector('input');
+ const file = new File(['hello'], 'hello.png', { type: 'image/png' });
+
+ uploadFile(input, file);
+
+ await delay(500);
+
+ requests[0].respond(
+ 201,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({
+ uri: 'https://www.example.com/product',
+ job_uri: 'https://www.example.com/job_uri',
+ }),
+ );
+
+ await delay(500);
+
+ expect(alert.getCall(0).args[0]).to.eq('Failed to create PDF');
+ });
+});
diff --git a/test/blocks/acom-widget/mocks/body.html b/test/blocks/acom-widget/mocks/body.html
new file mode 100644
index 00000000..6fa3246d
--- /dev/null
+++ b/test/blocks/acom-widget/mocks/body.html
@@ -0,0 +1,9 @@
+
+
+
diff --git a/test/blocks/acom-widget/mocks/head.html b/test/blocks/acom-widget/mocks/head.html
new file mode 100644
index 00000000..be4425f0
--- /dev/null
+++ b/test/blocks/acom-widget/mocks/head.html
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/test/integration/icon-block/icon-block_desktop.int.js b/test/integration/icon-block/icon-block_desktop.int.js
new file mode 100644
index 00000000..9f622def
--- /dev/null
+++ b/test/integration/icon-block/icon-block_desktop.int.js
@@ -0,0 +1,33 @@
+/* eslint-disable func-names */
+import {
+ readFile,
+ setViewport,
+ executeServerCommand,
+} from '@web/test-runner-commands';
+import { waitFor, delay } from '../../helpers/waitfor.js';
+
+const screenshotFolder = 'test/integration/icon-block/screenshots';
+
+describe('icon-block_desktop', function () {
+ const suiteName = this.title;
+ let testName;
+ let screenshotPath;
+
+ before(async () => {
+ document.head.innerHTML = await readFile({ path: '../mocks/head.html' });
+ document.body.innerHTML = await readFile({ path: './mocks/body.html' });
+ await setViewport({ width: 1200, height: 600 });
+ await import('../../../acrobat/scripts/scripts.js');
+ await waitFor(() => document.querySelector('.icon-block .icon-area'), 5000, 1000);
+ });
+
+ beforeEach(function () {
+ testName = this.currentTest.title;
+ screenshotPath = `${screenshotFolder}/${suiteName}/$browser/${testName}.png`;
+ });
+
+ it('icon-block_desktop', async () => {
+ await delay(1000);
+ await executeServerCommand('diff-screenshot', { path: screenshotPath });
+ });
+});
diff --git a/test/integration/icon-block/icon-block_mobile.int.js b/test/integration/icon-block/icon-block_mobile.int.js
new file mode 100644
index 00000000..6202b240
--- /dev/null
+++ b/test/integration/icon-block/icon-block_mobile.int.js
@@ -0,0 +1,33 @@
+/* eslint-disable func-names */
+import {
+ readFile,
+ setViewport,
+ executeServerCommand,
+} from '@web/test-runner-commands';
+import { waitFor, delay } from '../../helpers/waitfor.js';
+
+const screenshotFolder = 'test/integration/icon-block/screenshots';
+
+describe('icon-block_mobile', function () {
+ const suiteName = this.title;
+ let testName;
+ let screenshotPath;
+
+ before(async () => {
+ document.head.innerHTML = await readFile({ path: '../mocks/head.html' });
+ document.body.innerHTML = await readFile({ path: './mocks/body.html' });
+ await setViewport({ width: 500, height: 600 });
+ await import('../../../acrobat/scripts/scripts.js');
+ await waitFor(() => document.querySelector('.icon-block .icon-area'), 5000, 1000);
+ });
+
+ beforeEach(function () {
+ testName = this.currentTest.title;
+ screenshotPath = `${screenshotFolder}/${suiteName}/$browser/${testName}.png`;
+ });
+
+ it('icon-block_mobile', async () => {
+ await delay(1000);
+ await executeServerCommand('diff-screenshot', { path: screenshotPath });
+ });
+});
diff --git a/test/integration/icon-block/mocks/body.html b/test/integration/icon-block/mocks/body.html
new file mode 100644
index 00000000..3e96e7d7
--- /dev/null
+++ b/test/integration/icon-block/mocks/body.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Adobe Document Cloud
+
+ Whether you’re looking for basic information about Acrobat or
+ Acrobat Sign features and plans, or need a customized quote for your
+ unique environment, we’re here to help you.
+
+
+ Contact Sales
+
+
+
+
+
+
diff --git a/test/integration/icon-block/screenshots/icon-block_desktop/Chromium/icon-block_desktop.png b/test/integration/icon-block/screenshots/icon-block_desktop/Chromium/icon-block_desktop.png
new file mode 100644
index 00000000..eda951ff
Binary files /dev/null and b/test/integration/icon-block/screenshots/icon-block_desktop/Chromium/icon-block_desktop.png differ
diff --git a/test/integration/icon-block/screenshots/icon-block_desktop/Firefox/icon-block_desktop.png b/test/integration/icon-block/screenshots/icon-block_desktop/Firefox/icon-block_desktop.png
new file mode 100644
index 00000000..3ec53a03
Binary files /dev/null and b/test/integration/icon-block/screenshots/icon-block_desktop/Firefox/icon-block_desktop.png differ
diff --git a/test/integration/icon-block/screenshots/icon-block_desktop/Webkit/icon-block_desktop.png b/test/integration/icon-block/screenshots/icon-block_desktop/Webkit/icon-block_desktop.png
new file mode 100644
index 00000000..0a9623e8
Binary files /dev/null and b/test/integration/icon-block/screenshots/icon-block_desktop/Webkit/icon-block_desktop.png differ
diff --git a/test/integration/icon-block/screenshots/icon-block_mobile/Chromium/icon-block_mobile.png b/test/integration/icon-block/screenshots/icon-block_mobile/Chromium/icon-block_mobile.png
new file mode 100644
index 00000000..acd8a3cc
Binary files /dev/null and b/test/integration/icon-block/screenshots/icon-block_mobile/Chromium/icon-block_mobile.png differ
diff --git a/test/integration/icon-block/screenshots/icon-block_mobile/Firefox/icon-block_mobile.png b/test/integration/icon-block/screenshots/icon-block_mobile/Firefox/icon-block_mobile.png
new file mode 100644
index 00000000..af70099d
Binary files /dev/null and b/test/integration/icon-block/screenshots/icon-block_mobile/Firefox/icon-block_mobile.png differ
diff --git a/test/integration/icon-block/screenshots/icon-block_mobile/Webkit/icon-block_mobile.png b/test/integration/icon-block/screenshots/icon-block_mobile/Webkit/icon-block_mobile.png
new file mode 100644
index 00000000..9140c2d4
Binary files /dev/null and b/test/integration/icon-block/screenshots/icon-block_mobile/Webkit/icon-block_mobile.png differ
diff --git a/test/integration/media/media_desktop.int.js b/test/integration/media/media_desktop.int.js
new file mode 100644
index 00000000..267969fc
--- /dev/null
+++ b/test/integration/media/media_desktop.int.js
@@ -0,0 +1,33 @@
+/* eslint-disable func-names */
+import {
+ readFile,
+ setViewport,
+ executeServerCommand,
+} from '@web/test-runner-commands';
+import { waitFor, delay } from '../../helpers/waitfor.js';
+
+const screenshotFolder = 'test/integration/media/screenshots';
+
+describe('media_desktop', function () {
+ const suiteName = this.title;
+ let testName;
+ let screenshotPath;
+
+ before(async () => {
+ document.head.innerHTML = await readFile({ path: '../mocks/head.html' });
+ document.body.innerHTML = await readFile({ path: './mocks/body.html' });
+ await setViewport({ width: 1200, height: 600 });
+ await import('../../../acrobat/scripts/scripts.js');
+ await waitFor(() => document.querySelector('.media.qr-code'), 5000, 1000);
+ });
+
+ beforeEach(function () {
+ testName = this.currentTest.title;
+ screenshotPath = `${screenshotFolder}/${suiteName}/$browser/${testName}.png`;
+ });
+
+ it('media_desktop', async () => {
+ await delay(2000);
+ await executeServerCommand('diff-screenshot', { path: screenshotPath });
+ });
+});
diff --git a/test/integration/media/media_mobile.int.js b/test/integration/media/media_mobile.int.js
new file mode 100644
index 00000000..31a31248
--- /dev/null
+++ b/test/integration/media/media_mobile.int.js
@@ -0,0 +1,33 @@
+/* eslint-disable func-names */
+import {
+ readFile,
+ setViewport,
+ executeServerCommand,
+} from '@web/test-runner-commands';
+import { waitFor, delay } from '../../helpers/waitfor.js';
+
+const screenshotFolder = 'test/integration/media/screenshots';
+
+describe('media_mobile', function () {
+ const suiteName = this.title;
+ let testName;
+ let screenshotPath;
+
+ before(async () => {
+ document.head.innerHTML = await readFile({ path: '../mocks/head.html' });
+ document.body.innerHTML = await readFile({ path: './mocks/body.html' });
+ await setViewport({ width: 500, height: 600 });
+ await import('../../../acrobat/scripts/scripts.js');
+ await waitFor(() => document.querySelector('.media.qr-code'), 5000, 1000);
+ });
+
+ beforeEach(function () {
+ testName = this.currentTest.title;
+ screenshotPath = `${screenshotFolder}/${suiteName}/$browser/${testName}.png`;
+ });
+
+ it('media_mobile', async () => {
+ await delay(2000);
+ await executeServerCommand('diff-screenshot', { path: screenshotPath });
+ });
+});
diff --git a/test/integration/media/mocks/body.html b/test/integration/media/mocks/body.html
new file mode 100644
index 00000000..bcf410c0
--- /dev/null
+++ b/test/integration/media/mocks/body.html
@@ -0,0 +1,42 @@
+
+
+
diff --git a/test/integration/media/screenshots/media_desktop/Chromium/media_desktop.png b/test/integration/media/screenshots/media_desktop/Chromium/media_desktop.png
new file mode 100644
index 00000000..0dc2ff4c
Binary files /dev/null and b/test/integration/media/screenshots/media_desktop/Chromium/media_desktop.png differ
diff --git a/test/integration/media/screenshots/media_desktop/Firefox/media_desktop.png b/test/integration/media/screenshots/media_desktop/Firefox/media_desktop.png
new file mode 100644
index 00000000..dc2f8125
Binary files /dev/null and b/test/integration/media/screenshots/media_desktop/Firefox/media_desktop.png differ
diff --git a/test/integration/media/screenshots/media_desktop/Webkit/media_desktop.png b/test/integration/media/screenshots/media_desktop/Webkit/media_desktop.png
new file mode 100644
index 00000000..68c102b1
Binary files /dev/null and b/test/integration/media/screenshots/media_desktop/Webkit/media_desktop.png differ
diff --git a/test/integration/media/screenshots/media_mobile/Chromium/media_mobile.png b/test/integration/media/screenshots/media_mobile/Chromium/media_mobile.png
new file mode 100644
index 00000000..65aee323
Binary files /dev/null and b/test/integration/media/screenshots/media_mobile/Chromium/media_mobile.png differ
diff --git a/test/integration/media/screenshots/media_mobile/Firefox/media_mobile.png b/test/integration/media/screenshots/media_mobile/Firefox/media_mobile.png
new file mode 100644
index 00000000..4d2df0f6
Binary files /dev/null and b/test/integration/media/screenshots/media_mobile/Firefox/media_mobile.png differ
diff --git a/test/integration/media/screenshots/media_mobile/Webkit/media_mobile.png b/test/integration/media/screenshots/media_mobile/Webkit/media_mobile.png
new file mode 100644
index 00000000..c7ae8195
Binary files /dev/null and b/test/integration/media/screenshots/media_mobile/Webkit/media_mobile.png differ