feat: remove duplication of config in tests
This commit is contained in:
@@ -22,7 +22,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: ['test/**/**.ts'],
|
files: ['test/**/int.spec.ts'],
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/no-use-before-define': 'off',
|
'@typescript-eslint/no-use-before-define': 'off',
|
||||||
'@typescript-eslint/consistent-type-imports': 'warn',
|
'@typescript-eslint/consistent-type-imports': 'warn',
|
||||||
@@ -30,7 +30,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ['test/e2e/**/**.ts'],
|
files: ['test/**/e2e.spec.ts'],
|
||||||
extends: [
|
extends: [
|
||||||
'plugin:playwright/playwright-test'
|
'plugin:playwright/playwright-test'
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import type { PlaywrightTestConfig } from '@playwright/test';
|
|||||||
|
|
||||||
const config: PlaywrightTestConfig = {
|
const config: PlaywrightTestConfig = {
|
||||||
// Look for test files in the "tests" directory, relative to this configuration file
|
// Look for test files in the "tests" directory, relative to this configuration file
|
||||||
testDir: 'test/e2e',
|
testDir: 'test',
|
||||||
|
testMatch: 'e2e.spec.ts',
|
||||||
workers: 999,
|
workers: 999,
|
||||||
timeout: 600000,
|
timeout: 600000,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
@import '../../../../scss/styles';
|
|
||||||
|
|
||||||
.action-panel {
|
|
||||||
|
|
||||||
&__remove-row {
|
|
||||||
margin: 0 0 base(.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__add-row {
|
|
||||||
margin: base(.3) 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import Button from '../../../elements/Button';
|
|
||||||
import Popup from '../../../elements/Popup';
|
|
||||||
import BlockSelector from '../../field-types/Blocks/BlockSelector';
|
|
||||||
import { Props } from './types';
|
|
||||||
|
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
const baseClass = 'action-panel';
|
|
||||||
|
|
||||||
const ActionPanel: React.FC<Props> = (props) => {
|
|
||||||
const {
|
|
||||||
addRow,
|
|
||||||
removeRow,
|
|
||||||
label = 'Row',
|
|
||||||
blockType,
|
|
||||||
blocks = [],
|
|
||||||
rowIndex,
|
|
||||||
isHovered,
|
|
||||||
hasMaxRows,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const classes = [
|
|
||||||
baseClass,
|
|
||||||
].filter(Boolean).join(' ');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes}>
|
|
||||||
<Popup
|
|
||||||
showOnHover
|
|
||||||
size="wide"
|
|
||||||
color="dark"
|
|
||||||
horizontalAlign="right"
|
|
||||||
buttonType="custom"
|
|
||||||
button={(
|
|
||||||
<Button
|
|
||||||
className={`${baseClass}__remove-row`}
|
|
||||||
round
|
|
||||||
buttonStyle="none"
|
|
||||||
icon="x"
|
|
||||||
iconPosition="left"
|
|
||||||
iconStyle="with-border"
|
|
||||||
onClick={() => removeRow(rowIndex)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
Remove
|
|
||||||
{label}
|
|
||||||
</Popup>
|
|
||||||
|
|
||||||
{!hasMaxRows && (
|
|
||||||
<React.Fragment>
|
|
||||||
{blockType === 'blocks'
|
|
||||||
? (
|
|
||||||
<Popup
|
|
||||||
buttonType="custom"
|
|
||||||
size="large"
|
|
||||||
horizontalAlign="right"
|
|
||||||
button={(
|
|
||||||
<Button
|
|
||||||
className={`${baseClass}__add-row`}
|
|
||||||
round
|
|
||||||
buttonStyle="none"
|
|
||||||
icon="plus"
|
|
||||||
iconPosition="left"
|
|
||||||
iconStyle="with-border"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
render={({ close }) => (
|
|
||||||
<BlockSelector
|
|
||||||
blocks={blocks}
|
|
||||||
addRow={addRow}
|
|
||||||
addRowIndex={rowIndex}
|
|
||||||
close={close}
|
|
||||||
parentIsHovered={isHovered}
|
|
||||||
watchParentHover
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<Popup
|
|
||||||
showOnHover
|
|
||||||
size="wide"
|
|
||||||
color="dark"
|
|
||||||
horizontalAlign="center"
|
|
||||||
buttonType="custom"
|
|
||||||
button={(
|
|
||||||
<Button
|
|
||||||
className={`${baseClass}__add-row`}
|
|
||||||
round
|
|
||||||
buttonStyle="none"
|
|
||||||
icon="plus"
|
|
||||||
iconPosition="left"
|
|
||||||
iconStyle="with-border"
|
|
||||||
onClick={() => addRow(rowIndex)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
Add
|
|
||||||
{label}
|
|
||||||
</Popup>
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ActionPanel;
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { Block } from '../../../../../fields/config/types';
|
|
||||||
|
|
||||||
export type Props = {
|
|
||||||
label: string
|
|
||||||
addRow?: (index: number, blockType?: string) => void
|
|
||||||
removeRow?: (index: number) => void
|
|
||||||
blockType?: string
|
|
||||||
isHovered: boolean
|
|
||||||
rowIndex: number
|
|
||||||
blocks?: Block[]
|
|
||||||
hasMaxRows?: boolean
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
@import '../../../../scss/styles';
|
|
||||||
|
|
||||||
.position-panel {
|
|
||||||
&__move-backward {
|
|
||||||
transform: rotate(.5turn);
|
|
||||||
margin: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__move-forward {
|
|
||||||
margin: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__current-position {
|
|
||||||
text-align: center;
|
|
||||||
color: var(--theme-elevation-400);
|
|
||||||
}
|
|
||||||
|
|
||||||
padding-right: base(.5);
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import Button from '../../../elements/Button';
|
|
||||||
import { Props } from './types';
|
|
||||||
|
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
const baseClass = 'position-panel';
|
|
||||||
|
|
||||||
const PositionPanel: React.FC<Props> = (props) => {
|
|
||||||
const { moveRow, positionIndex, rowCount, readOnly } = props;
|
|
||||||
|
|
||||||
const adjustedIndex = positionIndex + 1;
|
|
||||||
|
|
||||||
const classes = [
|
|
||||||
baseClass,
|
|
||||||
`${baseClass}__${readOnly ? 'read-only' : ''}`,
|
|
||||||
].filter(Boolean).join(' ');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes}>
|
|
||||||
{!readOnly && (
|
|
||||||
<Button
|
|
||||||
className={`${baseClass}__move-backward ${positionIndex === 0 ? 'first-row' : ''}`}
|
|
||||||
buttonStyle="none"
|
|
||||||
icon="chevron"
|
|
||||||
round
|
|
||||||
onClick={() => moveRow(positionIndex, positionIndex - 1)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{(adjustedIndex && typeof positionIndex === 'number')
|
|
||||||
&& (
|
|
||||||
<div
|
|
||||||
className={`${baseClass}__current-position`}
|
|
||||||
>
|
|
||||||
{adjustedIndex >= 10 ? adjustedIndex : `0${adjustedIndex}`}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!readOnly && (
|
|
||||||
<Button
|
|
||||||
className={`${baseClass}__move-forward ${(positionIndex === rowCount - 1) ? 'last-row' : ''}`}
|
|
||||||
buttonStyle="none"
|
|
||||||
icon="chevron"
|
|
||||||
round
|
|
||||||
onClick={() => moveRow(positionIndex, positionIndex + 1)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default PositionPanel;
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export type Props = {
|
|
||||||
moveRow: (fromIndex: number, toIndex: number) => void
|
|
||||||
positionIndex: number
|
|
||||||
rowCount: number
|
|
||||||
readOnly: boolean
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
@import '../../../scss/styles.scss';
|
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
// COMPONENT STYLES
|
|
||||||
//////////////////////
|
|
||||||
|
|
||||||
.draggable-section {
|
|
||||||
padding-bottom: base(.5);
|
|
||||||
|
|
||||||
.draggable-section {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__content-wrapper {
|
|
||||||
display: flex;
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: $baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__section-header {
|
|
||||||
display: flex;
|
|
||||||
position: sticky;
|
|
||||||
top: $top-header-offset;
|
|
||||||
z-index: 1;
|
|
||||||
padding: base(.75) base(.75);
|
|
||||||
margin-left: - base(.75);
|
|
||||||
margin-right: - base(.75);
|
|
||||||
width: calc(100% + #{base(1.5)});
|
|
||||||
}
|
|
||||||
|
|
||||||
&__render-fields-wrapper {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-hovered>div {
|
|
||||||
>.field-type-gutter {
|
|
||||||
&.actions {
|
|
||||||
|
|
||||||
.field-type-gutter__content {
|
|
||||||
&:hover {
|
|
||||||
z-index: $z-nav;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-type-gutter__content-container {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-type-gutter__content-container {
|
|
||||||
box-shadow: #{$style-stroke-width-m} 0px 0px 0px var(--theme-elevation-800);
|
|
||||||
}
|
|
||||||
|
|
||||||
.position-panel__move-forward,
|
|
||||||
.position-panel__move-backward {
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
&.first-row,
|
|
||||||
&.last-row {
|
|
||||||
opacity: .15;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.position-panel__current-position {
|
|
||||||
color: var(--theme-elevation-800);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-collapse {
|
|
||||||
@include color-svg(var(--theme-elevation-0));
|
|
||||||
|
|
||||||
.btn__icon {
|
|
||||||
background-color: var(--theme-elevation-400);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--theme-elevation-800);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
label.field-label {
|
|
||||||
line-height: 1;
|
|
||||||
padding-bottom: base(.75)
|
|
||||||
}
|
|
||||||
|
|
||||||
@include mid-break {
|
|
||||||
min-width: base(16);
|
|
||||||
|
|
||||||
.position-panel__move-forward,
|
|
||||||
.position-panel__move-backward {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__section-header {
|
|
||||||
top: $top-header-offset-m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import AnimateHeight from 'react-animate-height';
|
|
||||||
import { Draggable } from 'react-beautiful-dnd';
|
|
||||||
|
|
||||||
import ActionPanel from './ActionPanel';
|
|
||||||
import SectionTitle from './SectionTitle';
|
|
||||||
import PositionPanel from './PositionPanel';
|
|
||||||
import Button from '../../elements/Button';
|
|
||||||
import { NegativeFieldGutterProvider } from '../FieldTypeGutter/context';
|
|
||||||
import FieldTypeGutter from '../FieldTypeGutter';
|
|
||||||
import RenderFields from '../RenderFields';
|
|
||||||
import { Props } from './types';
|
|
||||||
import HiddenInput from '../field-types/HiddenInput';
|
|
||||||
import { fieldAffectsData } from '../../../../fields/config/types';
|
|
||||||
|
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
const baseClass = 'draggable-section';
|
|
||||||
|
|
||||||
const DraggableSection: React.FC<Props> = (props) => {
|
|
||||||
const {
|
|
||||||
moveRow,
|
|
||||||
addRow,
|
|
||||||
removeRow,
|
|
||||||
rowIndex,
|
|
||||||
rowCount,
|
|
||||||
parentPath,
|
|
||||||
fieldSchema,
|
|
||||||
label,
|
|
||||||
blockType,
|
|
||||||
fieldTypes,
|
|
||||||
id,
|
|
||||||
setRowCollapse,
|
|
||||||
isCollapsed,
|
|
||||||
permissions,
|
|
||||||
readOnly,
|
|
||||||
hasMaxRows,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
|
||||||
|
|
||||||
const classes = [
|
|
||||||
baseClass,
|
|
||||||
isCollapsed ? 'is-collapsed' : 'is-open',
|
|
||||||
(isHovered && !readOnly) && 'is-hovered',
|
|
||||||
].filter(Boolean).join(' ');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Draggable
|
|
||||||
draggableId={id}
|
|
||||||
index={rowIndex}
|
|
||||||
isDragDisabled={readOnly}
|
|
||||||
>
|
|
||||||
{(providedDrag) => (
|
|
||||||
<div
|
|
||||||
ref={providedDrag.innerRef}
|
|
||||||
className={classes}
|
|
||||||
onMouseLeave={() => setIsHovered(false)}
|
|
||||||
onMouseOver={() => setIsHovered(true)}
|
|
||||||
onFocus={() => setIsHovered(true)}
|
|
||||||
{...providedDrag.draggableProps}
|
|
||||||
>
|
|
||||||
|
|
||||||
<div className={`${baseClass}__content-wrapper`}>
|
|
||||||
<FieldTypeGutter
|
|
||||||
variant="left"
|
|
||||||
dragHandleProps={providedDrag.dragHandleProps}
|
|
||||||
>
|
|
||||||
<PositionPanel
|
|
||||||
moveRow={moveRow}
|
|
||||||
rowCount={rowCount}
|
|
||||||
positionIndex={rowIndex}
|
|
||||||
readOnly={readOnly}
|
|
||||||
/>
|
|
||||||
</FieldTypeGutter>
|
|
||||||
|
|
||||||
<div className={`${baseClass}__render-fields-wrapper`}>
|
|
||||||
|
|
||||||
<AnimateHeight
|
|
||||||
height={isCollapsed ? 0 : 'auto'}
|
|
||||||
duration={200}
|
|
||||||
>
|
|
||||||
<NegativeFieldGutterProvider allow={false}>
|
|
||||||
<RenderFields
|
|
||||||
readOnly={readOnly}
|
|
||||||
fieldTypes={fieldTypes}
|
|
||||||
key={rowIndex}
|
|
||||||
permissions={permissions?.fields}
|
|
||||||
fieldSchema={fieldSchema.map((field) => ({
|
|
||||||
...field,
|
|
||||||
path: `${parentPath}.${rowIndex}${fieldAffectsData(field) ? `.${field.name}` : ''}`,
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</NegativeFieldGutterProvider>
|
|
||||||
</AnimateHeight>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<FieldTypeGutter
|
|
||||||
variant="right"
|
|
||||||
className="actions"
|
|
||||||
dragHandleProps={providedDrag.dragHandleProps}
|
|
||||||
>
|
|
||||||
{!readOnly && (
|
|
||||||
<ActionPanel
|
|
||||||
addRow={addRow}
|
|
||||||
removeRow={removeRow}
|
|
||||||
rowIndex={rowIndex}
|
|
||||||
label={label}
|
|
||||||
isHovered={isHovered}
|
|
||||||
hasMaxRows={hasMaxRows}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</FieldTypeGutter>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Draggable>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DraggableSection;
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { Field, Block } from '../../../../fields/config/types';
|
|
||||||
import { FieldTypes } from '../field-types';
|
|
||||||
import { FieldPermissions } from '../../../../auth/types';
|
|
||||||
|
|
||||||
export type Props = {
|
|
||||||
moveRow: (fromIndex: number, toIndex: number) => void
|
|
||||||
addRow: (index: number, blockType?: string) => void
|
|
||||||
removeRow: (index: number) => void
|
|
||||||
rowIndex: number
|
|
||||||
rowCount: number
|
|
||||||
parentPath: string
|
|
||||||
fieldSchema: Field[],
|
|
||||||
label?: string
|
|
||||||
blockType?: string
|
|
||||||
fieldTypes: FieldTypes
|
|
||||||
id: string
|
|
||||||
isCollapsed?: boolean
|
|
||||||
setRowCollapse?: (id: string, open: boolean) => void
|
|
||||||
positionPanelVerticalAlignment?: 'top' | 'center' | 'sticky'
|
|
||||||
actionPanelVerticalAlignment?: 'top' | 'center' | 'sticky'
|
|
||||||
permissions: FieldPermissions
|
|
||||||
readOnly: boolean
|
|
||||||
blocks?: Block[]
|
|
||||||
hasMaxRows?: boolean
|
|
||||||
}
|
|
||||||
@@ -12,9 +12,9 @@ require('@babel/register')({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [testConfigDir] = process.argv.slice(2);
|
const [testSuiteDir] = process.argv.slice(2);
|
||||||
|
|
||||||
const configPath = path.resolve(__dirname, '../', testConfigDir, 'config.ts');
|
const configPath = path.resolve(__dirname, '../', testSuiteDir, 'config.ts');
|
||||||
process.env.PAYLOAD_CONFIG_PATH = configPath;
|
process.env.PAYLOAD_CONFIG_PATH = configPath;
|
||||||
process.env.PAYLOAD_DROP_DATABASE = 'true';
|
process.env.PAYLOAD_DROP_DATABASE = 'true';
|
||||||
|
|
||||||
|
|||||||
1
test/e2e/uploads/.gitignore
vendored
1
test/e2e/uploads/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
/media
|
|
||||||
2
test/uploads/.gitignore
vendored
Normal file
2
test/uploads/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
!media/.gitkeep
|
||||||
|
media
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { buildConfig } from '../buildConfig';
|
import { buildConfig } from '../e2e/buildConfig';
|
||||||
import { devUser } from '../../credentials';
|
import { devUser } from '../credentials';
|
||||||
import getFileByPath from '../../../src/uploads/getFileByPath';
|
import getFileByPath from '../../src/uploads/getFileByPath';
|
||||||
|
|
||||||
export const mediaSlug = 'media';
|
export const mediaSlug = 'media';
|
||||||
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import type { Page } from '@playwright/test';
|
import type { Page } from '@playwright/test';
|
||||||
import { expect, test } from '@playwright/test';
|
import { expect, test } from '@playwright/test';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
|
|
||||||
import { initPayloadE2E } from '../../helpers/configHelpers';
|
|
||||||
import { login, saveDocAndAssert } from '../helpers';
|
|
||||||
import { relationSlug, mediaSlug } from './config';
|
import { relationSlug, mediaSlug } from './config';
|
||||||
import type { Media } from './payload-types';
|
import type { Media } from './payload-types';
|
||||||
import wait from '../../../src/utilities/wait';
|
import payload from '../../src';
|
||||||
import payload from '../../../src';
|
import { AdminUrlUtil } from '../helpers/adminUrlUtil';
|
||||||
|
import { initPayloadE2E } from '../helpers/configHelpers';
|
||||||
|
import { login, saveDocAndAssert } from '../e2e/helpers';
|
||||||
|
import wait from '../../src/utilities/wait';
|
||||||
|
|
||||||
const { beforeAll, describe } = test;
|
const { beforeAll, describe } = test;
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
0
test/uploads/int.spec.ts
Normal file
0
test/uploads/int.spec.ts
Normal file
Reference in New Issue
Block a user