feat: remove duplication of config in tests
This commit is contained in:
@@ -22,7 +22,7 @@ module.exports = {
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['test/**/**.ts'],
|
||||
files: ['test/**/int.spec.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'@typescript-eslint/consistent-type-imports': 'warn',
|
||||
@@ -30,7 +30,7 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['test/e2e/**/**.ts'],
|
||||
files: ['test/**/e2e.spec.ts'],
|
||||
extends: [
|
||||
'plugin:playwright/playwright-test'
|
||||
],
|
||||
|
||||
@@ -3,7 +3,8 @@ import type { PlaywrightTestConfig } from '@playwright/test';
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
// Look for test files in the "tests" directory, relative to this configuration file
|
||||
testDir: 'test/e2e',
|
||||
testDir: 'test',
|
||||
testMatch: 'e2e.spec.ts',
|
||||
workers: 999,
|
||||
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_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 fs from 'fs';
|
||||
import { buildConfig } from '../buildConfig';
|
||||
import { devUser } from '../../credentials';
|
||||
import getFileByPath from '../../../src/uploads/getFileByPath';
|
||||
import { buildConfig } from '../e2e/buildConfig';
|
||||
import { devUser } from '../credentials';
|
||||
import getFileByPath from '../../src/uploads/getFileByPath';
|
||||
|
||||
export const mediaSlug = 'media';
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
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 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;
|
||||
|
||||
|
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