Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Release] Stage to Main #2910

Merged
merged 13 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/label-zero-impact.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [eslint] reported by reviewdog 🐶
File ignored by default. Use a negated ignore pattern (like "--ignore-pattern '!<relative/path/to/filename>'") to override.

Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ const zeroImpactDirs = [
'.vscode',
'.test',
'.browserslistrc',
'libs/mep',
'.gitignore',
'.eslintrc.js',
'CODEOWNERS',
'web-test-runner.config.mjs',
'LICENSE',
'codecov.yaml',
'.gitignore',
'package.json',
'package-lock.json',
'test',
'libs/mep',
'nala'
];
const zeroImpactLabel = 'zero-impact';

Expand Down
1 change: 1 addition & 0 deletions .hlxignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ LICENSE
web-test-runner.config.mjs
codecov.yaml
libs/features/mas/*
!libs/features/mas/docs
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ https://feat-branch--project--owner.hlx.page/?milolibs=local (feature code, stag
```

## Testing
### Unit Testing
```sh
npm run test
```
Expand All @@ -69,3 +70,45 @@ npm run test:watch
### Coverage
`npm run test:watch` can give misleading coverage reports. Use `npm run test` for accurate coverage reporting.

### Nala E2E UI Testing
-----

#### 1. Running Nala Tests
Nala tests are run using the `npm run nala <env> [options]` command:

```sh
npm run nala <env> [options]
```
```sh
# env: [local | libs | branch | stage | etc ] default: local

# options:
- browser=<chrome|firefox|webkit> # Browser to use (default: chrome)
- device=<desktop|mobile> # Device (default: desktop)
- test=<.test.js> # Specific test file to run (runs all tests in the file)
- -g, --g=<@tag> # Tag to filter tests by annotations ex: @test1 @accordion @marquee
- mode=<headless|ui|debug|headed> # Mode (default: headless)
- config=<config-file> # Configuration file (default: Playwright default)
- project=<project-name> # Project configuration (default: milo-live-chromium)
- milolibs=<local|prod|feature|any|> # Milolibs?=<env>

```
#### 2. Nala Help Command:
To view examples of how to use Nala commands with various options, you can run
```sh
npm run nala help
```

#### ⚠️ Important Note
- **Debug and UI Mode Caution**: When using `debug` or `ui` mode, it is recommended to run only a single test using annotations (e.g., `@test1`). Running multiple tests in these modes (e.g., `npm run nala local mode=debug` or `mode=ui`) will launch a separate browser or debugger window for each test, which can quickly become resource-intensive and challenging to manage.

- **Tip**: To effectively watch or debug, focus on one test at a time to avoid opening excessive browser instances or debugger windows.

#### 3. Nala Documentation
For detailed guides and documentation on Nala, please visit the [Nala GitHub Wiki](https://github.com/adobecom/milo/wiki/Nala#nala-introduction).






17 changes: 11 additions & 6 deletions libs/blocks/bulk-publish-v2/components/bulk-publisher.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import './job-process.js';
import { LitElement, html } from '../../../deps/lit-all.min.js';
import { getSheet } from '../../../../tools/utils/utils.js';
import { authenticate, startJob } from '../services.js';
import { authenticate, getPublishable, startJob } from '../services.js';
import { getConfig } from '../../../utils/utils.js';
import {
delay,
Expand Down Expand Up @@ -95,7 +95,8 @@ class BulkPublish2 extends LitElement {
this.validateUrls();
}

setJobErrors(errors) {
setJobErrors(jobErrors, authErrors) {
const errors = [...jobErrors, ...authErrors];
const urls = [];
errors.forEach((error) => {
const matched = this.urls.filter((url) => {
Expand Down Expand Up @@ -323,7 +324,8 @@ class BulkPublish2 extends LitElement {
class="panel-title"
@click=${handleToggle}>
<span class="title">
Job Results
${this.jobs.length ? html`<strong>${this.jobs.length}</strong>` : ''}
Job Result${this.jobs.length > 1 ? 's' : ''}
</span>
<div class="jobs-tools${showList}">
<div
Expand Down Expand Up @@ -380,16 +382,17 @@ class BulkPublish2 extends LitElement {
async submit() {
if (!this.isDisabled()) {
this.processing = 'started';
const { authorized, unauthorized } = await getPublishable(this);
const job = await startJob({
urls: this.urls,
urls: authorized,
process: this.process.toLowerCase(),
useBulk: this.user.permissions[this.process]?.useBulk ?? false,
});
const { complete, error } = processJobResult(job);
this.jobs = [...this.jobs, ...complete];
this.processing = complete.length ? 'job' : false;
if (error.length) {
this.setJobErrors(error);
if (error.length || unauthorized.length) {
this.setJobErrors(error, unauthorized);
} else {
if (this.mode === 'full') this.openJobs = true;
this.reset();
Expand All @@ -407,6 +410,7 @@ class BulkPublish2 extends LitElement {

renderPromptLoader() {
setTimeout(() => {
/* c8 ignore next 4 */
const loader = this.renderRoot.querySelector('.load-indicator');
const message = this.renderRoot.querySelector('.message');
loader?.classList.add('hide');
Expand All @@ -427,6 +431,7 @@ class BulkPublish2 extends LitElement {
const canUse = Object.values(this.user.permissions).filter((perms) => perms.canUse);
if (canUse.length) return html``;
message = 'Current user is not authorized to use Bulk Publishing Tool';
/* c8 ignore next 3 */
} else {
message = 'Please sign in to AEM sidekick to continue';
}
Expand Down
25 changes: 25 additions & 0 deletions libs/blocks/bulk-publish-v2/services.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import userCanPublishPage from '../../tools/utils/publish.js';
import {
PROCESS_TYPES,
getErrorText,
Expand Down Expand Up @@ -246,8 +247,32 @@ const updateRetry = async ({ queue, urls, process }) => {
return newQueue;
};

// publish authentication service
const getPublishable = async ({ urls, process, user }) => {
let publishable = { authorized: [], unauthorized: [] };
if (!isLive(process)) {
publishable.authorized = urls;
} else {
const { permissions, profile } = user;
const live = { permissions: ['read'] };
if (permissions?.publish?.canUse) {
live.permissions.push('write');
}
publishable = await urls.reduce(async (init, url) => {
const result = await init;
const detail = { webPath: new URL(url).pathname, live, profile };
const { canPublish, message } = await userCanPublishPage(detail);
if (canPublish) result.authorized.push(url);
else result.unauthorized.push({ href: url, message });
return result;
}, Promise.resolve(publishable));
}
return publishable;
};

export {
authenticate,
getPublishable,
pollJobStatus,
startJob,
updateRetry,
Expand Down
11 changes: 9 additions & 2 deletions libs/blocks/global-navigation/global-navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import {
addMepHighlightAndTargetId,
isDarkMode,
darkIcons,
setDisableAEDState,
getDisableAEDState,
} from './utilities/utilities.js';

import { replaceKey, replaceKeyArray } from '../../features/placeholders.js';
Expand Down Expand Up @@ -837,8 +839,9 @@ class Gnav {

if (!hasActiveLink()) {
const sections = this.elements.mainNav.querySelectorAll('.feds-navItem--section');
const disableAED = getDisableAEDState();

if (sections.length === 1) {
if (!disableAED && sections.length === 1) {
sections[0].classList.add(selectors.activeNavItem.slice(1));
setActiveLink(true);
}
Expand Down Expand Up @@ -1024,7 +1027,11 @@ const getSource = async () => {
export default async function init(block) {
try {
const { mep } = getConfig();
const url = await getSource();
const sourceUrl = await getSource();
const [url, hash = ''] = sourceUrl.split('#');
if (hash === '_noActiveItem') {
setDisableAEDState();
}
const content = await fetchAndProcessPlainHtml({ url });
if (!content) return null;
const gnav = new Gnav({
Expand Down
14 changes: 12 additions & 2 deletions libs/blocks/global-navigation/utilities/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export function getAnalyticsValue(str, index) {

export function getExperienceName() {
const experiencePath = getMetadata('gnav-source');
const explicitExperience = experiencePath?.split('/').pop();
const explicitExperience = experiencePath?.split('#')[0]?.split('/').pop();
if (explicitExperience?.length
&& explicitExperience !== 'gnav') return explicitExperience;

Expand Down Expand Up @@ -257,14 +257,24 @@ export function setActiveDropdown(elem) {
});
}

// Disable AED(Active Element Detection)
export const [setDisableAEDState, getDisableAEDState] = (() => {
let disableAED = false;
return [
() => { disableAED = true; },
() => disableAED,
];
})();

export const [hasActiveLink, setActiveLink, getActiveLink] = (() => {
let activeLinkFound;

return [
() => activeLinkFound,
(val) => { activeLinkFound = !!val; },
(area) => {
if (hasActiveLink() || !(area instanceof HTMLElement)) return null;
const disableAED = getDisableAEDState();
if (disableAED || hasActiveLink() || !(area instanceof HTMLElement)) return null;
const { origin, pathname } = window.location;
const url = `${origin}${pathname}`;
const activeLink = [
Expand Down
6 changes: 6 additions & 0 deletions libs/blocks/hero-marquee/hero-marquee.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
decorateTextOverrides,
decorateButtons,
handleObjectFit,
loadCDT,
} from '../../utils/decorate.js';
import { createTag, loadStyle, getConfig } from '../../utils/utils.js';

Expand Down Expand Up @@ -259,5 +260,10 @@ export default async function init(el) {
}
});
decorateTextOverrides(el, ['-heading', '-body', '-detail'], mainCopy);

if (el.classList.contains('countdown-timer')) {
promiseArr.push(loadCDT(copy, el.classList));
}

await Promise.all(promiseArr);
}
6 changes: 4 additions & 2 deletions libs/blocks/library-config/library-config.css
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ input.sk-library-search-input:focus {
* Fixes block list getting cut off with search
* Margin height equal to search bar height
*/
.sk-library ul.con-blocks-list.inset {
.sk-library ul.con-blocks-list.inset,
.sk-library ul.con-templates-list.inset {
margin-bottom: 39px;
}

Expand Down Expand Up @@ -242,7 +243,8 @@ input.sk-library-search-input:focus {
font-weight: 700;
}

.sk-library .block-group.is-hidden {
.sk-library .block-group.is-hidden,
.con-templates-list .template.is-hidden {
display: none;
}

Expand Down
45 changes: 35 additions & 10 deletions libs/blocks/library-config/library-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { createTag } from '../../utils/utils.js';

const LIBRARY_PATH = '/docs/library/library.json';

async function loadBlocks(content, list, query) {
async function loadBlocks({ content, list, query, type }) {
const { default: blocks } = await import('./lists/blocks.js');
blocks(content, list, query);
blocks(content, list, query, type);
}

async function loadTemplates(content, list) {
async function loadTemplates({ content, list, query, type }) {
const { default: templates } = await import('./lists/templates.js');
templates(content, list);
templates(content, list, query, type);
}

async function loadPlaceholders(content, list) {
Expand All @@ -32,27 +32,47 @@ async function loadPersonalization(content, list) {
personalization(content, list);
}

function addSearch(content, list) {
function addSearch({ content, list, type }) {
const skLibrary = list.closest('.sk-library');
const header = skLibrary.querySelector('.sk-library-header');
let search = skLibrary.querySelector('.sk-library-search');
if (!search) {
search = createTag('div', { class: 'sk-library-search' });
const searchInput = createTag('input', { class: 'sk-library-search-input', placeholder: 'Search...' });
const clear = createTag('div', { class: 'sk-library-search-clear is-hidden' });

searchInput.addEventListener('input', (e) => {
const query = e.target.value;
if (query === '') {
clear.classList.add('is-hidden');
} else {
clear.classList.remove('is-hidden');
}
loadBlocks(content, list, query);

switch (type) {
case 'blocks':
loadBlocks({ content, list, query, type });
break;
case 'templates':
loadTemplates({ content, list, query, type });
break;
default:
}
});
clear.addEventListener('click', (e) => {
e.target.classList.add('is-hidden');
e.target.closest('.sk-library-search').querySelector('.sk-library-search-input').value = '';
loadBlocks(content, list);
const query = e.target.value;

switch (type) {
case 'blocks':
loadBlocks({ content, list, query, type });
break;
case 'templates':
loadTemplates({ content, list, query, type });
break;
default:
}
});
search.append(searchInput);
search.append(clear);
Expand All @@ -67,11 +87,12 @@ async function loadList(type, content, list) {
const query = list.closest('.sk-library').querySelector('.sk-library-search-input')?.value;
switch (type) {
case 'blocks':
addSearch(content, list);
loadBlocks(content, list, query);
addSearch({ content, list, type });
loadBlocks({ content, list, query, type });
break;
case 'templates':
loadTemplates(content, list);
addSearch({ content, list, type });
loadTemplates({ content, list, query, type });
break;
case 'placeholders':
loadPlaceholders(content, list);
Expand Down Expand Up @@ -198,6 +219,10 @@ function createHeader() {
el.classList.remove('inset');
});
skLibrary.classList.remove('allow-back');

// Remove library search if it's been added
const search = skLibrary.querySelector('.sk-library-search');
if (search) search.remove();
});
return header;
}
Expand Down
Loading
Loading