Compare commits

...

5 Commits

Author SHA1 Message Date
Sung-Hyun Kang
70ed0c79e1 Add data-testid 2025-12-11 10:25:28 -06:00
Sung-Hyun Kang
c2785ace83 Fix unit tests 2025-12-10 17:03:04 -06:00
Sung-Hyun Kang
bb5d3bfc42 Add data-testid to components for testing 2025-12-10 16:51:09 -06:00
Sung-Hyun Kang
98a21f2fb1 Fix cassandra tests 2025-12-10 11:19:09 -06:00
Sung-Hyun Kang
945c457bd5 Added different container creation playwirhgt tests 2025-12-09 19:07:54 -06:00
51 changed files with 1123 additions and 426 deletions

View File

@@ -14,7 +14,7 @@ export default defineConfig({
trace: "off", trace: "off",
video: "off", video: "off",
screenshot: "on", screenshot: "on",
testIdAttribute: "data-test", testIdAttribute: "data-testid",
contextOptions: { contextOptions: {
ignoreHTTPSErrors: true, ignoreHTTPSErrors: true,
}, },

View File

@@ -76,12 +76,10 @@ const mockedRbacUtils = RbacUtils as jest.Mocked<typeof RbacUtils>;
const mockedCopyJobPrerequisitesCache = CopyJobPrerequisitesCacheModule as jest.Mocked< const mockedCopyJobPrerequisitesCache = CopyJobPrerequisitesCacheModule as jest.Mocked<
typeof CopyJobPrerequisitesCacheModule typeof CopyJobPrerequisitesCacheModule
>; >;
interface TestWrapperProps { interface TestWrapperProps {
state: CopyJobContextState; state: CopyJobContextState;
onResult?: (result: PermissionGroupConfig[]) => void; onResult?: (result: PermissionGroupConfig[]) => void;
} }
const TestWrapper: React.FC<TestWrapperProps> = ({ state, onResult }) => { const TestWrapper: React.FC<TestWrapperProps> = ({ state, onResult }) => {
const result = usePermissionSections(state); const result = usePermissionSections(state);

View File

@@ -214,9 +214,9 @@ export const Dialog: FC = () => {
{contentHtml} {contentHtml}
{progressIndicatorProps && <ProgressIndicator {...progressIndicatorProps} />} {progressIndicatorProps && <ProgressIndicator {...progressIndicatorProps} />}
<DialogFooter> <DialogFooter>
<PrimaryButton {...primaryButtonProps} data-test={`DialogButton:${primaryButtonText}`} /> <PrimaryButton {...primaryButtonProps} data-testid={`DialogButton:${primaryButtonText}`} />
{secondaryButtonProps && ( {secondaryButtonProps && (
<DefaultButton {...secondaryButtonProps} data-test={`DialogButton:${secondaryButtonText}`} /> <DefaultButton {...secondaryButtonProps} data-testid={`DialogButton:${secondaryButtonText}`} />
)} )}
</DialogFooter> </DialogFooter>
</FluentDialog> </FluentDialog>

View File

@@ -137,7 +137,7 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
<Spinner size={SpinnerSize.large} className={this.props.spinnerClassName || "spinner"} /> <Spinner size={SpinnerSize.large} className={this.props.spinnerClassName || "spinner"} />
)} )}
<div <div
data-test="EditorReact/Host/Unloaded" data-testid="EditorReact/Host/Unloaded"
className={this.props.className || "jsonEditor"} className={this.props.className || "jsonEditor"}
style={this.props.monacoContainerStyles} style={this.props.monacoContainerStyles}
ref={(elt: HTMLElement) => this.setRef(elt)} ref={(elt: HTMLElement) => this.setRef(elt)}
@@ -148,7 +148,7 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
protected configureEditor(editor: monaco.editor.IStandaloneCodeEditor) { protected configureEditor(editor: monaco.editor.IStandaloneCodeEditor) {
this.editor = editor; this.editor = editor;
this.rootNode.dataset["test"] = "EditorReact/Host/Loaded"; this.rootNode.dataset["testid"] = "EditorReact/Host/Loaded";
// In development, we want to be able to access the editor instance from the console // In development, we want to be able to access the editor instance from the console
if (process.env.NODE_ENV === "development") { if (process.env.NODE_ENV === "development") {

View File

@@ -193,7 +193,7 @@ export const InputDataList: FC<InputDataListProps> = ({
<> <>
<Input <Input
id="filterInput" id="filterInput"
data-test={"DocumentsTab/FilterInput"} data-testid={"DocumentsTab/FilterInput"}
ref={inputRef} ref={inputRef}
type="text" type="text"
size="small" size="small"

View File

@@ -209,6 +209,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
checked={isAutoscaleSelected} checked={isAutoscaleSelected}
type="radio" type="radio"
role="radio" role="radio"
data-testid="ThroughputInput/ThroughputMode:Autoscale"
tabIndex={0} tabIndex={0}
onChange={(e) => handleOnChangeMode(e, "Autoscale")} onChange={(e) => handleOnChangeMode(e, "Autoscale")}
/> />
@@ -224,6 +225,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
type="radio" type="radio"
aria-required={true} aria-required={true}
role="radio" role="radio"
data-testid="ThroughputInput/ThroughputMode:Manual"
tabIndex={0} tabIndex={0}
onChange={(e) => handleOnChangeMode(e, "Manual")} onChange={(e) => handleOnChangeMode(e, "Manual")}
/> />
@@ -286,7 +288,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
</Stack> </Stack>
<TextField <TextField
id="autoscaleRUValueField" id="autoscaleRUValueField"
data-test="autoscaleRUInput" data-testid="ThroughputInput/AutoscaleRUInput"
type="number" type="number"
styles={{ styles={{
fieldGroup: { width: 100, height: 27, flexShrink: 0 }, fieldGroup: { width: 100, height: 27, flexShrink: 0 },
@@ -352,6 +354,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
} }
> >
<TextField <TextField
data-testid="ThroughputInput/ManualThroughputInput"
type="number" type="number"
styles={{ styles={{
fieldGroup: { width: 300, height: 27 }, fieldGroup: { width: 300, height: 27 },

View File

@@ -682,6 +682,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
aria-required={true} aria-required={true}
checked={true} checked={true}
className="throughputInputRadioBtn" className="throughputInputRadioBtn"
data-testid="ThroughputInput/ThroughputMode:Autoscale"
id="Autoscale-input" id="Autoscale-input"
onChange={[Function]} onChange={[Function]}
role="radio" role="radio"
@@ -699,6 +700,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
aria-required={true} aria-required={true}
checked={false} checked={false}
className="throughputInputRadioBtn" className="throughputInputRadioBtn"
data-testid="ThroughputInput/ThroughputMode:Manual"
id="Manual-input" id="Manual-input"
onChange={[Function]} onChange={[Function]}
role="radio" role="radio"
@@ -2144,7 +2146,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
</Stack> </Stack>
<StyledTextFieldBase <StyledTextFieldBase
ariaLabel="Container max RU/s" ariaLabel="Container max RU/s"
data-test="autoscaleRUInput" data-testid="ThroughputInput/AutoscaleRUInput"
errorMessage="" errorMessage=""
id="autoscaleRUValueField" id="autoscaleRUValueField"
key=".0:$.$.1" key=".0:$.$.1"
@@ -2171,7 +2173,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
> >
<TextFieldBase <TextFieldBase
ariaLabel="Container max RU/s" ariaLabel="Container max RU/s"
data-test="autoscaleRUInput" data-testid="ThroughputInput/AutoscaleRUInput"
deferredValidationTime={200} deferredValidationTime={200}
errorMessage="" errorMessage=""
id="autoscaleRUValueField" id="autoscaleRUValueField"
@@ -2472,7 +2474,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
aria-invalid={false} aria-invalid={false}
aria-label="Container max RU/s" aria-label="Container max RU/s"
className="ms-TextField-field field-124" className="ms-TextField-field field-124"
data-test="autoscaleRUInput" data-testid="ThroughputInput/AutoscaleRUInput"
id="autoscaleRUValueField" id="autoscaleRUValueField"
max="9007199254740991" max="9007199254740991"
min={1000} min={1000}

View File

@@ -139,7 +139,7 @@ export const TreeNodeComponent: React.FC<TreeNodeComponentProps> = ({
const contextMenuItems = (node.contextMenu ?? []).map((menuItem) => ( const contextMenuItems = (node.contextMenu ?? []).map((menuItem) => (
<MenuItem <MenuItem
data-test={`TreeNode/ContextMenuItem:${menuItem.label}`} data-testid={`TreeNode/ContextMenuItem:${menuItem.label}`}
disabled={menuItem.isDisabled} disabled={menuItem.isDisabled}
key={menuItem.label} key={menuItem.label}
onClick={() => menuItem.onClick(contextMenuRef)} onClick={() => menuItem.onClick(contextMenuRef)}
@@ -160,14 +160,14 @@ export const TreeNodeComponent: React.FC<TreeNodeComponentProps> = ({
const expandIcon = isLoading ? ( const expandIcon = isLoading ? (
<Spinner size="extra-tiny" /> <Spinner size="extra-tiny" />
) : !isBranch ? undefined : openItems.includes(treeNodeId) ? ( ) : !isBranch ? undefined : openItems.includes(treeNodeId) ? (
<ChevronDown20Regular data-test="TreeNode/CollapseIcon" /> <ChevronDown20Regular data-testid="TreeNode/CollapseIcon" />
) : ( ) : (
<ChevronRight20Regular data-text="TreeNode/ExpandIcon" /> <ChevronRight20Regular data-testid="TreeNode/ExpandIcon" />
); );
const treeItem = ( const treeItem = (
<TreeItem <TreeItem
data-test={`TreeNodeContainer:${treeNodeId}`} data-testid={`TreeNodeContainer:${treeNodeId}`}
value={treeNodeId} value={treeNodeId}
itemType={isBranch ? "branch" : "leaf"} itemType={isBranch ? "branch" : "leaf"}
onOpenChange={onOpenChange} onOpenChange={onOpenChange}
@@ -179,7 +179,7 @@ export const TreeNodeComponent: React.FC<TreeNodeComponentProps> = ({
shouldShowAsSelected && treeStyles.selectedItem, shouldShowAsSelected && treeStyles.selectedItem,
node.className && treeStyles[node.className], node.className && treeStyles[node.className],
)} )}
data-test={`TreeNode:${treeNodeId}`} data-testid={`TreeNode:${treeNodeId}`}
actions={ actions={
contextMenuItems.length > 0 && { contextMenuItems.length > 0 && {
className: treeStyles.actionsButtonContainer, className: treeStyles.actionsButtonContainer,
@@ -189,13 +189,13 @@ export const TreeNodeComponent: React.FC<TreeNodeComponentProps> = ({
<Button <Button
aria-label="More options" aria-label="More options"
className={mergeClasses(treeStyles.actionsButton, shouldShowAsSelected && treeStyles.selectedItem)} className={mergeClasses(treeStyles.actionsButton, shouldShowAsSelected && treeStyles.selectedItem)}
data-test="TreeNode/ContextMenuTrigger" data-testid="TreeNode/ContextMenuTrigger"
appearance="subtle" appearance="subtle"
ref={contextMenuRef} ref={contextMenuRef}
icon={<MoreHorizontal20Regular />} icon={<MoreHorizontal20Regular />}
/> />
</MenuTrigger> </MenuTrigger>
<MenuPopover data-test={`TreeNode/ContextMenu:${treeNodeId}`}> <MenuPopover data-testid={`TreeNode/ContextMenu:${treeNodeId}`}>
<MenuList>{contextMenuItems}</MenuList> <MenuList>{contextMenuItems}</MenuList>
</MenuPopover> </MenuPopover>
</Menu> </Menu>
@@ -208,7 +208,7 @@ export const TreeNodeComponent: React.FC<TreeNodeComponentProps> = ({
<span className={treeStyles.nodeLabel}>{node.label}</span> <span className={treeStyles.nodeLabel}>{node.label}</span>
</TreeItemLayout> </TreeItemLayout>
{!node.isLoading && node.children?.length > 0 && ( {!node.isLoading && node.children?.length > 0 && (
<Tree data-test={`Tree:${treeNodeId}`} className={treeStyles.tree}> <Tree data-testid={`Tree:${treeNodeId}`} className={treeStyles.tree}>
{getSortedChildren(node).map((childNode: TreeNode) => ( {getSortedChildren(node).map((childNode: TreeNode) => (
<TreeNodeComponent <TreeNodeComponent
openItems={openItems} openItems={openItems}

View File

@@ -3,7 +3,7 @@
exports[`TreeNodeComponent does not render children if the node is loading 1`] = ` exports[`TreeNodeComponent does not render children if the node is loading 1`] = `
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="branch" itemType="branch"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -11,10 +11,10 @@ exports[`TreeNodeComponent does not render children if the node is loading 1`] =
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
expandIcon={ expandIcon={
<ChevronRight20Regular <ChevronRight20Regular
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
/> />
} }
iconBefore={ iconBefore={
@@ -112,7 +112,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
> >
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="branch" itemType="branch"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -122,7 +122,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level={0} aria-level={0}
className="fui-TreeItem r15xhw3a" className="fui-TreeItem r15xhw3a"
data-fui-tree-item-value="root" data-fui-tree-item-value="root"
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
onChange={[Function]} onChange={[Function]}
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}
@@ -144,7 +144,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -164,7 +164,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
"layoutRef": { "layoutRef": {
"current": <div "current": <div
class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -173,7 +173,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -220,13 +220,13 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level="0" aria-level="0"
class="fui-TreeItem r15xhw3a" class="fui-TreeItem r15xhw3a"
data-fui-tree-item-value="root" data-fui-tree-item-value="root"
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
role="treeitem" role="treeitem"
tabindex="-1" tabindex="-1"
> >
<div <div
class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -235,7 +235,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -270,7 +270,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
</div> </div>
<div <div
class="fui-Tree rnv2ez3 ___17a32do_7zrvj80 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n" class="fui-Tree rnv2ez3 ___17a32do_7zrvj80 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n"
data-test="Tree:root" data-testid="Tree:root"
role="tree" role="tree"
> >
<div <div
@@ -278,13 +278,13 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level="1" aria-level="1"
class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd" class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd"
data-fui-tree-item-value="root/child1Label" data-fui-tree-item-value="root/child1Label"
data-test="TreeNodeContainer:root/child1Label" data-testid="TreeNodeContainer:root/child1Label"
role="treeitem" role="treeitem"
tabindex="0" tabindex="0"
> >
<div <div
class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child1Label" data-testid="TreeNode:root/child1Label"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -293,7 +293,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -332,13 +332,13 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level="1" aria-level="1"
class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd" class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd"
data-fui-tree-item-value="root/child2LoadingLabel" data-fui-tree-item-value="root/child2LoadingLabel"
data-test="TreeNodeContainer:root/child2LoadingLabel" data-testid="TreeNodeContainer:root/child2LoadingLabel"
role="treeitem" role="treeitem"
tabindex="-1" tabindex="-1"
> >
<div <div
class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child2LoadingLabel" data-testid="TreeNode:root/child2LoadingLabel"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -347,7 +347,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -385,13 +385,13 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level="1" aria-level="1"
class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd" class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd"
data-fui-tree-item-value="root/child3ExpandingLabel" data-fui-tree-item-value="root/child3ExpandingLabel"
data-test="TreeNodeContainer:root/child3ExpandingLabel" data-testid="TreeNodeContainer:root/child3ExpandingLabel"
role="treeitem" role="treeitem"
tabindex="-1" tabindex="-1"
> >
<div <div
class="fui-TreeItemLayout r1bx0xiv ___dxcrnh0_vz3p260 fk6fouc fkhj508 figsok6 f1i3iumi f1k1erfc fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___dxcrnh0_vz3p260 fk6fouc fkhj508 figsok6 f1i3iumi f1k1erfc fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child3ExpandingLabel" data-testid="TreeNode:root/child3ExpandingLabel"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -441,10 +441,10 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
expandIcon={ expandIcon={
<ChevronRight20Regular <ChevronRight20Regular
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
/> />
} }
iconBefore={ iconBefore={
@@ -457,19 +457,19 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
> >
<div <div
className="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
> >
<div <div
aria-hidden={true} aria-hidden={true}
className="fui-TreeItemLayout__expandIcon rh4pu5o" className="fui-TreeItemLayout__expandIcon rh4pu5o"
> >
<ChevronRight20Regular <ChevronRight20Regular
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
> >
<svg <svg
aria-hidden={true} aria-hidden={true}
className="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" className="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -506,7 +506,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
</TreeItemLayout> </TreeItemLayout>
<Tree <Tree
className="___17a32do_0000000 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n" className="___17a32do_0000000 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n"
data-test="Tree:root" data-testid="Tree:root"
> >
<TreeProvider <TreeProvider
value={ value={
@@ -574,7 +574,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
> >
<div <div
className="fui-Tree rnv2ez3 ___17a32do_7zrvj80 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n" className="fui-Tree rnv2ez3 ___17a32do_7zrvj80 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n"
data-test="Tree:root" data-testid="Tree:root"
role="tree" role="tree"
> >
<TreeNodeComponent <TreeNodeComponent
@@ -610,7 +610,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
> >
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root/child1Label" data-testid="TreeNodeContainer:root/child1Label"
itemType="branch" itemType="branch"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root/child1Label" value="root/child1Label"
@@ -620,7 +620,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level={1} aria-level={1}
className="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd" className="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd"
data-fui-tree-item-value="root/child1Label" data-fui-tree-item-value="root/child1Label"
data-test="TreeNodeContainer:root/child1Label" data-testid="TreeNodeContainer:root/child1Label"
onChange={[Function]} onChange={[Function]}
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}
@@ -642,7 +642,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -662,7 +662,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
"layoutRef": { "layoutRef": {
"current": <div "current": <div
class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child1Label" data-testid="TreeNode:root/child1Label"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -671,7 +671,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -718,13 +718,13 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level="1" aria-level="1"
class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd" class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd"
data-fui-tree-item-value="root/child1Label" data-fui-tree-item-value="root/child1Label"
data-test="TreeNodeContainer:root/child1Label" data-testid="TreeNodeContainer:root/child1Label"
role="treeitem" role="treeitem"
tabindex="0" tabindex="0"
> >
<div <div
class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child1Label" data-testid="TreeNode:root/child1Label"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -733,7 +733,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -775,10 +775,10 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child1Label" data-testid="TreeNode:root/child1Label"
expandIcon={ expandIcon={
<ChevronRight20Regular <ChevronRight20Regular
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
/> />
} }
iconBefore={ iconBefore={
@@ -791,19 +791,19 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
> >
<div <div
className="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child1Label" data-testid="TreeNode:root/child1Label"
> >
<div <div
aria-hidden={true} aria-hidden={true}
className="fui-TreeItemLayout__expandIcon rh4pu5o" className="fui-TreeItemLayout__expandIcon rh4pu5o"
> >
<ChevronRight20Regular <ChevronRight20Regular
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
> >
<svg <svg
aria-hidden={true} aria-hidden={true}
className="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" className="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -840,7 +840,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
</TreeItemLayout> </TreeItemLayout>
<Tree <Tree
className="___17a32do_0000000 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n" className="___17a32do_0000000 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n"
data-test="Tree:root/child1Label" data-testid="Tree:root/child1Label"
> >
<TreeProvider <TreeProvider
value={ value={
@@ -881,7 +881,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
> >
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root/child2LoadingLabel" data-testid="TreeNodeContainer:root/child2LoadingLabel"
itemType="branch" itemType="branch"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root/child2LoadingLabel" value="root/child2LoadingLabel"
@@ -891,7 +891,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level={1} aria-level={1}
className="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd" className="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd"
data-fui-tree-item-value="root/child2LoadingLabel" data-fui-tree-item-value="root/child2LoadingLabel"
data-test="TreeNodeContainer:root/child2LoadingLabel" data-testid="TreeNodeContainer:root/child2LoadingLabel"
onChange={[Function]} onChange={[Function]}
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}
@@ -913,7 +913,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -933,7 +933,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
"layoutRef": { "layoutRef": {
"current": <div "current": <div
class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child2LoadingLabel" data-testid="TreeNode:root/child2LoadingLabel"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -942,7 +942,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -989,13 +989,13 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level="1" aria-level="1"
class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd" class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd"
data-fui-tree-item-value="root/child2LoadingLabel" data-fui-tree-item-value="root/child2LoadingLabel"
data-test="TreeNodeContainer:root/child2LoadingLabel" data-testid="TreeNodeContainer:root/child2LoadingLabel"
role="treeitem" role="treeitem"
tabindex="-1" tabindex="-1"
> >
<div <div
class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child2LoadingLabel" data-testid="TreeNode:root/child2LoadingLabel"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -1004,7 +1004,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<svg <svg
aria-hidden="true" aria-hidden="true"
class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" class="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -1046,10 +1046,10 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child2LoadingLabel" data-testid="TreeNode:root/child2LoadingLabel"
expandIcon={ expandIcon={
<ChevronRight20Regular <ChevronRight20Regular
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
/> />
} }
iconBefore={ iconBefore={
@@ -1062,19 +1062,19 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
> >
<div <div
className="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="fui-TreeItemLayout r1bx0xiv ___9uolwu0_9b0r4g0 fk6fouc fkhj508 figsok6 f1i3iumi fo100m9 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child2LoadingLabel" data-testid="TreeNode:root/child2LoadingLabel"
> >
<div <div
aria-hidden={true} aria-hidden={true}
className="fui-TreeItemLayout__expandIcon rh4pu5o" className="fui-TreeItemLayout__expandIcon rh4pu5o"
> >
<ChevronRight20Regular <ChevronRight20Regular
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
> >
<svg <svg
aria-hidden={true} aria-hidden={true}
className="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0" className="___12fm75w_v8ls9a0 f1w7gpdv fez10in fg4l7m0"
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
fill="currentColor" fill="currentColor"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
@@ -1140,7 +1140,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
> >
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root/child3ExpandingLabel" data-testid="TreeNodeContainer:root/child3ExpandingLabel"
itemType="leaf" itemType="leaf"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root/child3ExpandingLabel" value="root/child3ExpandingLabel"
@@ -1149,7 +1149,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level={1} aria-level={1}
className="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd" className="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd"
data-fui-tree-item-value="root/child3ExpandingLabel" data-fui-tree-item-value="root/child3ExpandingLabel"
data-test="TreeNodeContainer:root/child3ExpandingLabel" data-testid="TreeNodeContainer:root/child3ExpandingLabel"
onChange={[Function]} onChange={[Function]}
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}
@@ -1188,7 +1188,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
"layoutRef": { "layoutRef": {
"current": <div "current": <div
class="fui-TreeItemLayout r1bx0xiv ___dxcrnh0_vz3p260 fk6fouc fkhj508 figsok6 f1i3iumi f1k1erfc fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___dxcrnh0_vz3p260 fk6fouc fkhj508 figsok6 f1i3iumi f1k1erfc fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child3ExpandingLabel" data-testid="TreeNode:root/child3ExpandingLabel"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -1240,13 +1240,13 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
aria-level="1" aria-level="1"
class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd" class="fui-TreeItem r15xhw3a ___jer8zr0_6no3ah0 f10bgyvd"
data-fui-tree-item-value="root/child3ExpandingLabel" data-fui-tree-item-value="root/child3ExpandingLabel"
data-test="TreeNodeContainer:root/child3ExpandingLabel" data-testid="TreeNodeContainer:root/child3ExpandingLabel"
role="treeitem" role="treeitem"
tabindex="-1" tabindex="-1"
> >
<div <div
class="fui-TreeItemLayout r1bx0xiv ___dxcrnh0_vz3p260 fk6fouc fkhj508 figsok6 f1i3iumi f1k1erfc fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" class="fui-TreeItemLayout r1bx0xiv ___dxcrnh0_vz3p260 fk6fouc fkhj508 figsok6 f1i3iumi f1k1erfc fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child3ExpandingLabel" data-testid="TreeNode:root/child3ExpandingLabel"
> >
<div <div
aria-hidden="true" aria-hidden="true"
@@ -1294,7 +1294,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child3ExpandingLabel" data-testid="TreeNode:root/child3ExpandingLabel"
iconBefore={ iconBefore={
<img <img
alt="" alt=""
@@ -1305,7 +1305,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
> >
<div <div
className="fui-TreeItemLayout r1bx0xiv ___dxcrnh0_vz3p260 fk6fouc fkhj508 figsok6 f1i3iumi f1k1erfc fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="fui-TreeItemLayout r1bx0xiv ___dxcrnh0_vz3p260 fk6fouc fkhj508 figsok6 f1i3iumi f1k1erfc fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root/child3ExpandingLabel" data-testid="TreeNode:root/child3ExpandingLabel"
> >
<div <div
aria-hidden={true} aria-hidden={true}
@@ -1345,7 +1345,7 @@ exports[`TreeNodeComponent fully renders a tree 1`] = `
exports[`TreeNodeComponent renders a loading spinner if the node is loading: loaded 1`] = ` exports[`TreeNodeComponent renders a loading spinner if the node is loading: loaded 1`] = `
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="leaf" itemType="leaf"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -1353,7 +1353,7 @@ exports[`TreeNodeComponent renders a loading spinner if the node is loading: loa
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
iconBefore={ iconBefore={
<img <img
alt="" alt=""
@@ -1374,7 +1374,7 @@ exports[`TreeNodeComponent renders a loading spinner if the node is loading: loa
exports[`TreeNodeComponent renders a loading spinner if the node is loading: loading 1`] = ` exports[`TreeNodeComponent renders a loading spinner if the node is loading: loading 1`] = `
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="leaf" itemType="leaf"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -1382,7 +1382,7 @@ exports[`TreeNodeComponent renders a loading spinner if the node is loading: loa
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
expandIcon={ expandIcon={
<Spinner <Spinner
size="extra-tiny" size="extra-tiny"
@@ -1408,7 +1408,7 @@ exports[`TreeNodeComponent renders a loading spinner if the node is loading: loa
exports[`TreeNodeComponent renders a node as expandable if it has empty, but defined, children array 1`] = ` exports[`TreeNodeComponent renders a node as expandable if it has empty, but defined, children array 1`] = `
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="branch" itemType="branch"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -1416,10 +1416,10 @@ exports[`TreeNodeComponent renders a node as expandable if it has empty, but def
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
expandIcon={ expandIcon={
<ChevronRight20Regular <ChevronRight20Regular
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
/> />
} }
iconBefore={ iconBefore={
@@ -1450,7 +1450,7 @@ exports[`TreeNodeComponent renders a node with a menu 1`] = `
> >
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="leaf" itemType="leaf"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -1468,22 +1468,22 @@ exports[`TreeNodeComponent renders a node with a menu 1`] = `
appearance="subtle" appearance="subtle"
aria-label="More options" aria-label="More options"
className="___1pg0eu5_pgl3ex0 f1twygmj" className="___1pg0eu5_pgl3ex0 f1twygmj"
data-test="TreeNode/ContextMenuTrigger" data-testid="TreeNode/ContextMenuTrigger"
icon={<MoreHorizontal20Regular />} icon={<MoreHorizontal20Regular />}
/> />
</MenuTrigger> </MenuTrigger>
<MenuPopover <MenuPopover
data-test="TreeNode/ContextMenu:root" data-testid="TreeNode/ContextMenu:root"
> >
<MenuList> <MenuList>
<MenuItem <MenuItem
data-test="TreeNode/ContextMenuItem:enabledItem" data-testid="TreeNode/ContextMenuItem:enabledItem"
onClick={[Function]} onClick={[Function]}
> >
enabledItem enabledItem
</MenuItem> </MenuItem>
<MenuItem <MenuItem
data-test="TreeNode/ContextMenuItem:disabledItem" data-testid="TreeNode/ContextMenuItem:disabledItem"
disabled={true} disabled={true}
onClick={[Function]} onClick={[Function]}
> >
@@ -1496,7 +1496,7 @@ exports[`TreeNodeComponent renders a node with a menu 1`] = `
} }
} }
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
iconBefore={ iconBefore={
<img <img
alt="" alt=""
@@ -1516,14 +1516,14 @@ exports[`TreeNodeComponent renders a node with a menu 1`] = `
<MenuPopover> <MenuPopover>
<MenuList> <MenuList>
<MenuItem <MenuItem
data-test="TreeNode/ContextMenuItem:enabledItem" data-testid="TreeNode/ContextMenuItem:enabledItem"
key="enabledItem" key="enabledItem"
onClick={[Function]} onClick={[Function]}
> >
enabledItem enabledItem
</MenuItem> </MenuItem>
<MenuItem <MenuItem
data-test="TreeNode/ContextMenuItem:disabledItem" data-testid="TreeNode/ContextMenuItem:disabledItem"
disabled={true} disabled={true}
key="disabledItem" key="disabledItem"
onClick={[Function]} onClick={[Function]}
@@ -1538,7 +1538,7 @@ exports[`TreeNodeComponent renders a node with a menu 1`] = `
exports[`TreeNodeComponent renders a single node 1`] = ` exports[`TreeNodeComponent renders a single node 1`] = `
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="leaf" itemType="leaf"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -1546,7 +1546,7 @@ exports[`TreeNodeComponent renders a single node 1`] = `
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
iconBefore={ iconBefore={
<img <img
alt="" alt=""
@@ -1567,7 +1567,7 @@ exports[`TreeNodeComponent renders a single node 1`] = `
exports[`TreeNodeComponent renders an icon if the node has one 1`] = ` exports[`TreeNodeComponent renders an icon if the node has one 1`] = `
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="leaf" itemType="leaf"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -1575,7 +1575,7 @@ exports[`TreeNodeComponent renders an icon if the node has one 1`] = `
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
iconBefore={ iconBefore={
<img <img
alt="" alt=""
@@ -1596,7 +1596,7 @@ exports[`TreeNodeComponent renders an icon if the node has one 1`] = `
exports[`TreeNodeComponent renders selected parent node as selected if no descendant nodes are selected 1`] = ` exports[`TreeNodeComponent renders selected parent node as selected if no descendant nodes are selected 1`] = `
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="branch" itemType="branch"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -1604,10 +1604,10 @@ exports[`TreeNodeComponent renders selected parent node as selected if no descen
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___rq9vxg0_1ykn2d2 fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1nfm20t f1do9gdl" className="___rq9vxg0_1ykn2d2 fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1nfm20t f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
expandIcon={ expandIcon={
<ChevronRight20Regular <ChevronRight20Regular
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
/> />
} }
iconBefore={ iconBefore={
@@ -1626,7 +1626,7 @@ exports[`TreeNodeComponent renders selected parent node as selected if no descen
</TreeItemLayout> </TreeItemLayout>
<Tree <Tree
className="___17a32do_0000000 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n" className="___17a32do_0000000 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n"
data-test="Tree:root" data-testid="Tree:root"
> >
<TreeNodeComponent <TreeNodeComponent
key="child1Label" key="child1Label"
@@ -1679,7 +1679,7 @@ exports[`TreeNodeComponent renders selected parent node as selected if no descen
exports[`TreeNodeComponent renders selected parent node as unselected if any descendant node is selected 1`] = ` exports[`TreeNodeComponent renders selected parent node as unselected if any descendant node is selected 1`] = `
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="branch" itemType="branch"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -1687,10 +1687,10 @@ exports[`TreeNodeComponent renders selected parent node as unselected if any des
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl" className="___z7owk70_14ep1pe fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
expandIcon={ expandIcon={
<ChevronRight20Regular <ChevronRight20Regular
data-text="TreeNode/ExpandIcon" data-testid="TreeNode/ExpandIcon"
/> />
} }
iconBefore={ iconBefore={
@@ -1709,7 +1709,7 @@ exports[`TreeNodeComponent renders selected parent node as unselected if any des
</TreeItemLayout> </TreeItemLayout>
<Tree <Tree
className="___17a32do_0000000 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n" className="___17a32do_0000000 f1acs6jw f11qra4b fepn2xe f1nbblvp f19d5ny4 fzz4f4n"
data-test="Tree:root" data-testid="Tree:root"
> >
<TreeNodeComponent <TreeNodeComponent
key="child1Label" key="child1Label"
@@ -1763,7 +1763,7 @@ exports[`TreeNodeComponent renders selected parent node as unselected if any des
exports[`TreeNodeComponent renders single selected leaf node as selected 1`] = ` exports[`TreeNodeComponent renders single selected leaf node as selected 1`] = `
<TreeItem <TreeItem
className="" className=""
data-test="TreeNodeContainer:root" data-testid="TreeNodeContainer:root"
itemType="leaf" itemType="leaf"
onOpenChange={[Function]} onOpenChange={[Function]}
value="root" value="root"
@@ -1771,7 +1771,7 @@ exports[`TreeNodeComponent renders single selected leaf node as selected 1`] = `
<TreeItemLayout <TreeItemLayout
actions={false} actions={false}
className="___rq9vxg0_1ykn2d2 fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1nfm20t f1do9gdl" className="___rq9vxg0_1ykn2d2 fkhj508 fbv8p0b f1f09k3d fg706s2 frpde29 f1n8cmsf f1ktbui8 f1nfm20t f1do9gdl"
data-test="TreeNode:root" data-testid="TreeNode:root"
iconBefore={ iconBefore={
<img <img
alt="" alt=""

View File

@@ -76,7 +76,7 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
name: label, name: label,
disabled: btn.disabled, disabled: btn.disabled,
ariaLabel: btn.ariaLabel, ariaLabel: btn.ariaLabel,
"data-test": `CommandBar/Button:${label}`, "data-testid": `CommandBar/Button:${label}`,
buttonStyles: { buttonStyles: {
root: { root: {
backgroundColor: backgroundColor, backgroundColor: backgroundColor,

View File

@@ -133,7 +133,7 @@ export class NotificationConsoleComponent extends React.Component<
</span> </span>
</span> </span>
</div> </div>
<div className="expandCollapseButton" data-test="NotificationConsole/ExpandCollapseButton"> <div className="expandCollapseButton" data-testid="NotificationConsole/ExpandCollapseButton">
<img <img
src={this.props.isConsoleExpanded ? ChevronDownIcon : ChevronUpIcon} src={this.props.isConsoleExpanded ? ChevronDownIcon : ChevronUpIcon}
alt={this.props.isConsoleExpanded ? "Collapse icon" : "Expand icon"} alt={this.props.isConsoleExpanded ? "Collapse icon" : "Expand icon"}
@@ -145,7 +145,7 @@ export class NotificationConsoleComponent extends React.Component<
height={this.props.isConsoleExpanded ? "auto" : 0} height={this.props.isConsoleExpanded ? "auto" : 0}
onAnimationEnd={this.onConsoleWasExpanded} onAnimationEnd={this.onConsoleWasExpanded}
> >
<div data-test="NotificationConsole/Contents" className="notificationConsoleContents"> <div data-testid="NotificationConsole/Contents" className="notificationConsoleContents">
<div className="notificationConsoleControls"> <div className="notificationConsoleControls">
<Dropdown <Dropdown
label="Filter:" label="Filter:"

View File

@@ -88,7 +88,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
</div> </div>
<div <div
className="expandCollapseButton" className="expandCollapseButton"
data-test="NotificationConsole/ExpandCollapseButton" data-testid="NotificationConsole/ExpandCollapseButton"
> >
<img <img
alt="Expand icon" alt="Expand icon"
@@ -122,7 +122,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
> >
<div <div
className="notificationConsoleContents" className="notificationConsoleContents"
data-test="NotificationConsole/Contents" data-testid="NotificationConsole/Contents"
> >
<div <div
className="notificationConsoleControls" className="notificationConsoleControls"
@@ -273,7 +273,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
</div> </div>
<div <div
className="expandCollapseButton" className="expandCollapseButton"
data-test="NotificationConsole/ExpandCollapseButton" data-testid="NotificationConsole/ExpandCollapseButton"
> >
<img <img
alt="Expand icon" alt="Expand icon"
@@ -307,7 +307,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
> >
<div <div
className="notificationConsoleContents" className="notificationConsoleContents"
data-test="NotificationConsole/Contents" data-testid="NotificationConsole/Contents"
> >
<div <div
className="notificationConsoleControls" className="notificationConsoleControls"

View File

@@ -56,16 +56,16 @@ export class StatusBar extends React.Component<Props> {
return ( return (
<BarContainer> <BarContainer>
<Bar data-test="notebookStatusBar"> <Bar data-testid="notebookStatusBar">
<RightStatus> <RightStatus>
{this.props.lastSaved ? ( {this.props.lastSaved ? (
<p data-test="saveStatus"> Last saved {distanceInWordsToNow(this.props.lastSaved)} </p> <p data-testid="saveStatus"> Last saved {distanceInWordsToNow(this.props.lastSaved)} </p>
) : ( ) : (
<p> Not saved yet </p> <p> Not saved yet </p>
)} )}
</RightStatus> </RightStatus>
<LeftStatus> <LeftStatus>
<p data-test="kernelStatus"> <p data-testid="kernelStatus">
{name} | {this.props.kernelStatus} {name} | {this.props.kernelStatus}
</p> </p>
</LeftStatus> </LeftStatus>

View File

@@ -301,6 +301,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
type="radio" type="radio"
role="radio" role="radio"
id="databaseCreateNew" id="databaseCreateNew"
data-testid="AddCollectionPanel/DatabaseRadio:CreateNew"
tabIndex={0} tabIndex={0}
onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)} onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)}
/> />
@@ -314,6 +315,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
name="databaseType" name="databaseType"
type="radio" type="radio"
role="radio" role="radio"
data-testid="AddCollectionPanel/DatabaseRadio:UseExisting"
tabIndex={0} tabIndex={0}
onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)} onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)}
/> />
@@ -337,6 +339,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
size={40} size={40}
className="panelTextField" className="panelTextField"
aria-label="New database id, Type a new database id" aria-label="New database id, Type a new database id"
data-testid="AddCollectionPanel/DatabaseId"
tabIndex={0} tabIndex={0}
value={this.state.newDatabaseId} value={this.state.newDatabaseId}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
@@ -346,18 +349,20 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
{!isServerlessAccount() && ( {!isServerlessAccount() && (
<Stack horizontal> <Stack horizontal>
<Checkbox <div data-testid="AddCollectionPanel/SharedThroughputCheckbox">
label={`Share throughput across ${getCollectionName(true).toLocaleLowerCase()}`} <Checkbox
checked={this.state.isSharedThroughputChecked} label={`Share throughput across ${getCollectionName(true).toLocaleLowerCase()}`}
styles={{ checked={this.state.isSharedThroughputChecked}
text: { fontSize: 12 }, styles={{
checkbox: { width: 12, height: 12 }, text: { fontSize: 12 },
label: { padding: 0, alignItems: "center" }, checkbox: { width: 12, height: 12 },
}} label: { padding: 0, alignItems: "center" },
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) => }}
this.setState({ isSharedThroughputChecked: isChecked }) onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
} this.setState({ isSharedThroughputChecked: isChecked })
/> }
/>
</div>
<TooltipHost <TooltipHost
directionalHint={DirectionalHint.bottomLeftEdge} directionalHint={DirectionalHint.bottomLeftEdge}
content={`Throughput configured at the database level will be shared across all ${getCollectionName( content={`Throughput configured at the database level will be shared across all ${getCollectionName(
@@ -396,6 +401,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
{!this.state.createNewDatabase && ( {!this.state.createNewDatabase && (
<Dropdown <Dropdown
ariaLabel="Choose an existing database" ariaLabel="Choose an existing database"
data-testid="AddCollectionPanel/ExistingDatabaseDropdown"
styles={{ title: { height: 27, lineHeight: 27 }, dropdownItem: { fontSize: 12 } }} styles={{ title: { height: 27, lineHeight: 27 }, dropdownItem: { fontSize: 12 } }}
style={{ width: 300, fontSize: 12 }} style={{ width: 300, fontSize: 12 }}
placeholder="Choose an existing database" placeholder="Choose an existing database"
@@ -443,6 +449,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
placeholder={`e.g., ${getCollectionName()}1`} placeholder={`e.g., ${getCollectionName()}1`}
size={40} size={40}
className="panelTextField" className="panelTextField"
data-testid="AddCollectionPanel/CollectionId"
aria-label={`${getCollectionName()} id, Example ${getCollectionName()}1`} aria-label={`${getCollectionName()} id, Example ${getCollectionName()}1`}
value={this.state.collectionId} value={this.state.collectionId}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
@@ -576,6 +583,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
<input <input
type="text" type="text"
id="addCollection-partitionKeyValue" id="addCollection-partitionKeyValue"
data-testid="AddCollectionPanel/PartitionKey"
aria-required aria-required
required required
size={40} size={40}
@@ -612,6 +620,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
<input <input
type="text" type="text"
id="addCollection-partitionKeyValue" id="addCollection-partitionKeyValue"
data-testid="AddCollectionPanel/PartitionKey"
key={`addCollection-partitionKeyValue_${index}`} key={`addCollection-partitionKeyValue_${index}`}
aria-required aria-required
required required
@@ -729,7 +738,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
)} )}
{!isFabricNative() && userContext.apiType === "SQL" && ( {!isFabricNative() && userContext.apiType === "SQL" && (
<Stack style={{ marginTop: -2, marginBottom: -4 }}> <Stack style={{ marginTop: -2, marginBottom: -4 }} data-testid="AddCollectionPanel/UniqueKeysSection">
{UniqueKeysHeader()} {UniqueKeysHeader()}
{this.state.uniqueKeys.map((uniqueKey: string, i: number): JSX.Element => { {this.state.uniqueKeys.map((uniqueKey: string, i: number): JSX.Element => {
return ( return (
@@ -743,6 +752,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
: "Comma separated paths e.g. /firstName,/address/zipCode" : "Comma separated paths e.g. /firstName,/address/zipCode"
} }
className="panelTextField" className="panelTextField"
data-testid="AddCollectionPanel/UniqueKey"
value={uniqueKey} value={uniqueKey}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => { onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
const uniqueKeys = this.state.uniqueKeys.map((uniqueKey: string, j: number) => { const uniqueKeys = this.state.uniqueKeys.map((uniqueKey: string, j: number) => {
@@ -769,6 +779,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
<ActionButton <ActionButton
iconProps={{ iconName: "Add" }} iconProps={{ iconName: "Add" }}
data-testid="AddCollectionPanel/AddUniqueKeyButton"
styles={{ root: { padding: 0 }, label: { fontSize: 12 } }} styles={{ root: { padding: 0 }, label: { fontSize: 12 } }}
onClick={() => this.setState({ uniqueKeys: [...this.state.uniqueKeys, ""] })} onClick={() => this.setState({ uniqueKeys: [...this.state.uniqueKeys, ""] })}
> >

View File

@@ -56,6 +56,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
aria-label="Create new database" aria-label="Create new database"
checked={true} checked={true}
className="panelRadioBtn" className="panelRadioBtn"
data-testid="AddCollectionPanel/DatabaseRadio:CreateNew"
id="databaseCreateNew" id="databaseCreateNew"
name="databaseType" name="databaseType"
onChange={[Function]} onChange={[Function]}
@@ -73,6 +74,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
aria-label="Use existing database" aria-label="Use existing database"
checked={false} checked={false}
className="panelRadioBtn" className="panelRadioBtn"
data-testid="AddCollectionPanel/DatabaseRadio:UseExisting"
name="databaseType" name="databaseType"
onChange={[Function]} onChange={[Function]}
role="radio" role="radio"
@@ -94,6 +96,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
aria-required={true} aria-required={true}
autoComplete="off" autoComplete="off"
className="panelTextField" className="panelTextField"
data-testid="AddCollectionPanel/DatabaseId"
id="newDatabaseId" id="newDatabaseId"
name="newDatabaseId" name="newDatabaseId"
onChange={[Function]} onChange={[Function]}
@@ -109,26 +112,30 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
<Stack <Stack
horizontal={true} horizontal={true}
> >
<StyledCheckboxBase <div
checked={false} data-testid="AddCollectionPanel/SharedThroughputCheckbox"
label="Share throughput across containers" >
onChange={[Function]} <StyledCheckboxBase
styles={ checked={false}
{ label="Share throughput across containers"
"checkbox": { onChange={[Function]}
"height": 12, styles={
"width": 12, {
}, "checkbox": {
"label": { "height": 12,
"alignItems": "center", "width": 12,
"padding": 0, },
}, "label": {
"text": { "alignItems": "center",
"fontSize": 12, "padding": 0,
}, },
"text": {
"fontSize": 12,
},
}
} }
} />
/> </div>
<StyledTooltipHostBase <StyledTooltipHostBase
content="Throughput configured at the database level will be shared across all containers within the database." content="Throughput configured at the database level will be shared across all containers within the database."
directionalHint={4} directionalHint={4}
@@ -191,6 +198,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
aria-required={true} aria-required={true}
autoComplete="off" autoComplete="off"
className="panelTextField" className="panelTextField"
data-testid="AddCollectionPanel/CollectionId"
id="collectionId" id="collectionId"
name="collectionId" name="collectionId"
onChange={[Function]} onChange={[Function]}
@@ -252,6 +260,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
aria-label="Partition key" aria-label="Partition key"
aria-required={true} aria-required={true}
className="panelTextField" className="panelTextField"
data-testid="AddCollectionPanel/PartitionKey"
id="addCollection-partitionKeyValue" id="addCollection-partitionKeyValue"
onChange={[Function]} onChange={[Function]}
pattern=".*" pattern=".*"
@@ -304,6 +313,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
setThroughputValue={[Function]} setThroughputValue={[Function]}
/> />
<Stack <Stack
data-testid="AddCollectionPanel/UniqueKeysSection"
style={ style={
{ {
"marginBottom": -4, "marginBottom": -4,
@@ -338,6 +348,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
</StyledTooltipHostBase> </StyledTooltipHostBase>
</Stack> </Stack>
<CustomizedActionButton <CustomizedActionButton
data-testid="AddCollectionPanel/AddUniqueKeyButton"
iconProps={ iconProps={
{ {
"iconName": "Add", "iconName": "Add",

View File

@@ -199,6 +199,7 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
{keyspaceCreateNew && ( {keyspaceCreateNew && (
<Stack className="panelGroupSpacing"> <Stack className="panelGroupSpacing">
<TextField <TextField
data-testid="AddCollectionPanel/DatabaseId"
aria-required="true" aria-required="true"
required={true} required={true}
autoComplete="off" autoComplete="off"
@@ -215,16 +216,20 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
{!isServerlessAccount() && ( {!isServerlessAccount() && (
<Stack horizontal> <Stack horizontal>
<Checkbox <div data-testid="AddCollectionPanel/SharedThroughputCheckbox">
label="Provision shared throughput" <Checkbox
checked={isKeyspaceShared} label="Provision shared throughput"
styles={{ checked={isKeyspaceShared}
text: { fontSize: 12 }, styles={{
checkbox: { width: 12, height: 12 }, text: { fontSize: 12 },
label: { padding: 0, alignItems: "center" }, checkbox: { width: 12, height: 12 },
}} label: { padding: 0, alignItems: "center" },
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) => setIsKeyspaceShared(isChecked)} }}
/> onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
setIsKeyspaceShared(isChecked)
}
/>
</div>
<InfoTooltip> <InfoTooltip>
Provisioned throughput at the keyspace level will be shared across unlimited number of tables within Provisioned throughput at the keyspace level will be shared across unlimited number of tables within
the keyspace the keyspace
@@ -287,6 +292,7 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
{`CREATE TABLE ${keyspaceCreateNew ? newKeyspaceId : existingKeyspaceId}.`} {`CREATE TABLE ${keyspaceCreateNew ? newKeyspaceId : existingKeyspaceId}.`}
</Text> </Text>
<TextField <TextField
data-testid="AddCollectionPanel/CollectionId"
underlined underlined
styles={getTextFieldStyles({ fontSize: 12, width: 150 })} styles={getTextFieldStyles({ fontSize: 12, width: 150 })}
aria-required="true" aria-required="true"

View File

@@ -120,6 +120,7 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
<Text variant="small">Confirm by typing the {collectionName.toLowerCase()} id</Text> <Text variant="small">Confirm by typing the {collectionName.toLowerCase()} id</Text>
<TextField <TextField
id="confirmCollectionId" id="confirmCollectionId"
data-testid="DeleteCollectionConfirmationPane/ConfirmInput"
autoFocus autoFocus
value={inputCollectionName} value={inputCollectionName}
styles={{ fieldGroup: { width: 300 } }} styles={{ fieldGroup: { width: 300 } }}

View File

@@ -42,6 +42,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
<StyledTextFieldBase <StyledTextFieldBase
ariaLabel="Confirm by typing the container id" ariaLabel="Confirm by typing the container id"
autoFocus={true} autoFocus={true}
data-testid="DeleteCollectionConfirmationPane/ConfirmInput"
id="confirmCollectionId" id="confirmCollectionId"
onChange={[Function]} onChange={[Function]}
required={true} required={true}
@@ -57,6 +58,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
<TextFieldBase <TextFieldBase
ariaLabel="Confirm by typing the container id" ariaLabel="Confirm by typing the container id"
autoFocus={true} autoFocus={true}
data-testid="DeleteCollectionConfirmationPane/ConfirmInput"
deferredValidationTime={200} deferredValidationTime={200}
id="confirmCollectionId" id="confirmCollectionId"
onChange={[Function]} onChange={[Function]}
@@ -353,6 +355,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
aria-label="Confirm by typing the container id" aria-label="Confirm by typing the container id"
autoFocus={true} autoFocus={true}
className="ms-TextField-field field-113" className="ms-TextField-field field-113"
data-testid="DeleteCollectionConfirmationPane/ConfirmInput"
id="confirmCollectionId" id="confirmCollectionId"
onBlur={[Function]} onBlur={[Function]}
onChange={[Function]} onChange={[Function]}
@@ -379,7 +382,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
> >
<CustomizedPrimaryButton <CustomizedPrimaryButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
text="OK" text="OK"
@@ -390,7 +393,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
> >
<PrimaryButton <PrimaryButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
styles={ styles={
@@ -681,7 +684,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
> >
<CustomizedDefaultButton <CustomizedDefaultButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -977,7 +980,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
> >
<DefaultButton <DefaultButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -1271,7 +1274,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
<BaseButton <BaseButton
ariaLabel="OK" ariaLabel="OK"
baseClassName="ms-Button" baseClassName="ms-Button"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -2157,7 +2160,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
aria-label="OK" aria-label="OK"
className="ms-Button ms-Button--primary root-122" className="ms-Button ms-Button--primary root-122"
data-is-focusable={true} data-is-focusable={true}
data-test="Panel/OkButton" data-testid="Panel/OkButton"
id="sidePanelOkButton" id="sidePanelOkButton"
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}

View File

@@ -135,7 +135,7 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
<Text variant="small">{confirmDatabase}</Text> <Text variant="small">{confirmDatabase}</Text>
<TextField <TextField
id="confirmDatabaseId" id="confirmDatabaseId"
data-test="Input:confirmDatabaseId" data-testid="DeleteDatabaseConfirmationPanel/ConfirmInput"
autoFocus autoFocus
styles={{ fieldGroup: { width: 300 } }} styles={{ fieldGroup: { width: 300 } }}
onChange={(event, newInput?: string) => { onChange={(event, newInput?: string) => {

View File

@@ -5312,7 +5312,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
> >
<CustomizedPrimaryButton <CustomizedPrimaryButton
ariaLabel="Execute" ariaLabel="Execute"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
text="Execute" text="Execute"
@@ -5323,7 +5323,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
> >
<PrimaryButton <PrimaryButton
ariaLabel="Execute" ariaLabel="Execute"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
styles={ styles={
@@ -5614,7 +5614,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
> >
<CustomizedDefaultButton <CustomizedDefaultButton
ariaLabel="Execute" ariaLabel="Execute"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -5910,7 +5910,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
> >
<DefaultButton <DefaultButton
ariaLabel="Execute" ariaLabel="Execute"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -6204,7 +6204,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
<BaseButton <BaseButton
ariaLabel="Execute" ariaLabel="Execute"
baseClassName="ms-Button" baseClassName="ms-Button"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -7090,7 +7090,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
aria-label="Execute" aria-label="Execute"
className="ms-Button ms-Button--primary root-148" className="ms-Button ms-Button--primary root-148"
data-is-focusable={true} data-is-focusable={true}
data-test="Panel/OkButton" data-testid="Panel/OkButton"
id="sidePanelOkButton" id="sidePanelOkButton"
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}

View File

@@ -54,7 +54,7 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
return ( return (
<Panel <Panel
data-test={`Panel:${this.props.headerText}`} data-testid={`Panel:${this.props.headerText}`}
headerText={this.props.headerText} headerText={this.props.headerText}
isOpen={this.props.isOpen} isOpen={this.props.isOpen}
onDismiss={this.onDissmiss} onDismiss={this.onDissmiss}

View File

@@ -16,7 +16,7 @@ export const PanelFooterComponent: React.FunctionComponent<PanelFooterProps> = (
<PrimaryButton <PrimaryButton
type="submit" type="submit"
id="sidePanelOkButton" id="sidePanelOkButton"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
text={buttonLabel} text={buttonLabel}
ariaLabel={buttonLabel} ariaLabel={buttonLabel}
disabled={!!isButtonDisabled} disabled={!!isButtonDisabled}

View File

@@ -21,7 +21,7 @@ exports[`Right Pane Form should render Default properly 1`] = `
> >
<CustomizedPrimaryButton <CustomizedPrimaryButton
ariaLabel="Load" ariaLabel="Load"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
text="Load" text="Load"
@@ -32,7 +32,7 @@ exports[`Right Pane Form should render Default properly 1`] = `
> >
<PrimaryButton <PrimaryButton
ariaLabel="Load" ariaLabel="Load"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
styles={ styles={
@@ -323,7 +323,7 @@ exports[`Right Pane Form should render Default properly 1`] = `
> >
<CustomizedDefaultButton <CustomizedDefaultButton
ariaLabel="Load" ariaLabel="Load"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -619,7 +619,7 @@ exports[`Right Pane Form should render Default properly 1`] = `
> >
<DefaultButton <DefaultButton
ariaLabel="Load" ariaLabel="Load"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -913,7 +913,7 @@ exports[`Right Pane Form should render Default properly 1`] = `
<BaseButton <BaseButton
ariaLabel="Load" ariaLabel="Load"
baseClassName="ms-Button" baseClassName="ms-Button"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -1799,7 +1799,7 @@ exports[`Right Pane Form should render Default properly 1`] = `
aria-label="Load" aria-label="Load"
className="ms-Button ms-Button--primary root-109" className="ms-Button ms-Button--primary root-109"
data-is-focusable={true} data-is-focusable={true}
data-test="Panel/OkButton" data-testid="Panel/OkButton"
id="sidePanelOkButton" id="sidePanelOkButton"
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}

View File

@@ -688,7 +688,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
> >
<CustomizedPrimaryButton <CustomizedPrimaryButton
ariaLabel="Create" ariaLabel="Create"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
text="Create" text="Create"
@@ -699,7 +699,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
> >
<PrimaryButton <PrimaryButton
ariaLabel="Create" ariaLabel="Create"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
styles={ styles={
@@ -990,7 +990,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
> >
<CustomizedDefaultButton <CustomizedDefaultButton
ariaLabel="Create" ariaLabel="Create"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -1286,7 +1286,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
> >
<DefaultButton <DefaultButton
ariaLabel="Create" ariaLabel="Create"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -1580,7 +1580,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
<BaseButton <BaseButton
ariaLabel="Create" ariaLabel="Create"
baseClassName="ms-Button" baseClassName="ms-Button"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -2466,7 +2466,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
aria-label="Create" aria-label="Create"
className="ms-Button ms-Button--primary root-128" className="ms-Button ms-Button--primary root-128"
data-is-focusable={true} data-is-focusable={true}
data-test="Panel/OkButton" data-testid="Panel/OkButton"
id="sidePanelOkButton" id="sidePanelOkButton"
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}

View File

@@ -1258,7 +1258,7 @@ exports[`Table query select Panel should render Default properly 1`] = `
> >
<CustomizedPrimaryButton <CustomizedPrimaryButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
text="OK" text="OK"
@@ -1269,7 +1269,7 @@ exports[`Table query select Panel should render Default properly 1`] = `
> >
<PrimaryButton <PrimaryButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
styles={ styles={
@@ -1560,7 +1560,7 @@ exports[`Table query select Panel should render Default properly 1`] = `
> >
<CustomizedDefaultButton <CustomizedDefaultButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -1856,7 +1856,7 @@ exports[`Table query select Panel should render Default properly 1`] = `
> >
<DefaultButton <DefaultButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -2150,7 +2150,7 @@ exports[`Table query select Panel should render Default properly 1`] = `
<BaseButton <BaseButton
ariaLabel="OK" ariaLabel="OK"
baseClassName="ms-Button" baseClassName="ms-Button"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -3036,7 +3036,7 @@ exports[`Table query select Panel should render Default properly 1`] = `
aria-label="OK" aria-label="OK"
className="ms-Button ms-Button--primary root-125" className="ms-Button ms-Button--primary root-125"
data-is-focusable={true} data-is-focusable={true}
data-test="Panel/OkButton" data-testid="Panel/OkButton"
id="sidePanelOkButton" id="sidePanelOkButton"
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}

View File

@@ -369,7 +369,7 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
> >
<CustomizedPrimaryButton <CustomizedPrimaryButton
ariaLabel="Add Entity" ariaLabel="Add Entity"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
text="Add Entity" text="Add Entity"
@@ -380,7 +380,7 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
> >
<PrimaryButton <PrimaryButton
ariaLabel="Add Entity" ariaLabel="Add Entity"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
styles={ styles={
@@ -671,7 +671,7 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
> >
<CustomizedDefaultButton <CustomizedDefaultButton
ariaLabel="Add Entity" ariaLabel="Add Entity"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -967,7 +967,7 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
> >
<DefaultButton <DefaultButton
ariaLabel="Add Entity" ariaLabel="Add Entity"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -1261,7 +1261,7 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
<BaseButton <BaseButton
ariaLabel="Add Entity" ariaLabel="Add Entity"
baseClassName="ms-Button" baseClassName="ms-Button"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -2147,7 +2147,7 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
aria-label="Add Entity" aria-label="Add Entity"
className="ms-Button ms-Button--primary root-113" className="ms-Button ms-Button--primary root-113"
data-is-focusable={true} data-is-focusable={true}
data-test="Panel/OkButton" data-testid="Panel/OkButton"
id="sidePanelOkButton" id="sidePanelOkButton"
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}

View File

@@ -375,7 +375,7 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
> >
<CustomizedPrimaryButton <CustomizedPrimaryButton
ariaLabel="Update" ariaLabel="Update"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
text="Update" text="Update"
@@ -386,7 +386,7 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
> >
<PrimaryButton <PrimaryButton
ariaLabel="Update" ariaLabel="Update"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
styles={ styles={
@@ -677,7 +677,7 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
> >
<CustomizedDefaultButton <CustomizedDefaultButton
ariaLabel="Update" ariaLabel="Update"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -973,7 +973,7 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
> >
<DefaultButton <DefaultButton
ariaLabel="Update" ariaLabel="Update"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -1267,7 +1267,7 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
<BaseButton <BaseButton
ariaLabel="Update" ariaLabel="Update"
baseClassName="ms-Button" baseClassName="ms-Button"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -2153,7 +2153,7 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
aria-label="Update" aria-label="Update"
className="ms-Button ms-Button--primary root-113" className="ms-Button ms-Button--primary root-113"
data-is-focusable={true} data-is-focusable={true}
data-test="Panel/OkButton" data-testid="Panel/OkButton"
id="sidePanelOkButton" id="sidePanelOkButton"
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}

View File

@@ -367,7 +367,7 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
<StyledTextFieldBase <StyledTextFieldBase
ariaLabel="Confirm by typing the Database id (name)" ariaLabel="Confirm by typing the Database id (name)"
autoFocus={true} autoFocus={true}
data-test="Input:confirmDatabaseId" data-testid="DeleteDatabaseConfirmationPanel/ConfirmInput"
id="confirmDatabaseId" id="confirmDatabaseId"
onChange={[Function]} onChange={[Function]}
required={true} required={true}
@@ -382,7 +382,7 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
<TextFieldBase <TextFieldBase
ariaLabel="Confirm by typing the Database id (name)" ariaLabel="Confirm by typing the Database id (name)"
autoFocus={true} autoFocus={true}
data-test="Input:confirmDatabaseId" data-testid="DeleteDatabaseConfirmationPanel/ConfirmInput"
deferredValidationTime={200} deferredValidationTime={200}
id="confirmDatabaseId" id="confirmDatabaseId"
onChange={[Function]} onChange={[Function]}
@@ -678,7 +678,7 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
aria-label="Confirm by typing the Database id (name)" aria-label="Confirm by typing the Database id (name)"
autoFocus={true} autoFocus={true}
className="ms-TextField-field field-117" className="ms-TextField-field field-117"
data-test="Input:confirmDatabaseId" data-testid="DeleteDatabaseConfirmationPanel/ConfirmInput"
id="confirmDatabaseId" id="confirmDatabaseId"
onBlur={[Function]} onBlur={[Function]}
onChange={[Function]} onChange={[Function]}
@@ -1054,7 +1054,7 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
> >
<CustomizedPrimaryButton <CustomizedPrimaryButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
text="OK" text="OK"
@@ -1065,7 +1065,7 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
> >
<PrimaryButton <PrimaryButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
styles={ styles={
@@ -1356,7 +1356,7 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
> >
<CustomizedDefaultButton <CustomizedDefaultButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -1652,7 +1652,7 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
> >
<DefaultButton <DefaultButton
ariaLabel="OK" ariaLabel="OK"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -1946,7 +1946,7 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
<BaseButton <BaseButton
ariaLabel="OK" ariaLabel="OK"
baseClassName="ms-Button" baseClassName="ms-Button"
data-test="Panel/OkButton" data-testid="Panel/OkButton"
disabled={false} disabled={false}
id="sidePanelOkButton" id="sidePanelOkButton"
onRenderDescription={[Function]} onRenderDescription={[Function]}
@@ -2832,7 +2832,7 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
aria-label="OK" aria-label="OK"
className="ms-Button ms-Button--primary root-130" className="ms-Button ms-Button--primary root-130"
data-is-focusable={true} data-is-focusable={true}
data-test="Panel/OkButton" data-testid="Panel/OkButton"
id="sidePanelOkButton" id="sidePanelOkButton"
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}

View File

@@ -4,7 +4,7 @@ exports[`PaneContainerComponent test should be resize if notification console is
<StyledPanelBase <StyledPanelBase
closeButtonAriaLabel="Close test" closeButtonAriaLabel="Close test"
customWidth="440px" customWidth="440px"
data-test="Panel:test" data-testid="Panel:test"
headerClassName="panelHeader" headerClassName="panelHeader"
headerText="test" headerText="test"
isFooterAtBottom={true} isFooterAtBottom={true}
@@ -43,7 +43,7 @@ exports[`PaneContainerComponent test should not render console with panel 1`] =
<StyledPanelBase <StyledPanelBase
closeButtonAriaLabel="Close test" closeButtonAriaLabel="Close test"
customWidth="440px" customWidth="440px"
data-test="Panel:test" data-testid="Panel:test"
headerClassName="panelHeader" headerClassName="panelHeader"
headerText="test" headerText="test"
isFooterAtBottom={true} isFooterAtBottom={true}
@@ -84,7 +84,7 @@ exports[`PaneContainerComponent test should render with panel content and header
<StyledPanelBase <StyledPanelBase
closeButtonAriaLabel="Close test" closeButtonAriaLabel="Close test"
customWidth="440px" customWidth="440px"
data-test="Panel:test" data-testid="Panel:test"
headerClassName="panelHeader" headerClassName="panelHeader"
headerText="test" headerText="test"
isFooterAtBottom={true} isFooterAtBottom={true}

View File

@@ -242,9 +242,14 @@ const GlobalCommands: React.FC<GlobalCommandsProps> = ({ explorer }) => {
} }
return ( return (
<div className={styles.globalCommandsContainer} data-test="GlobalCommands"> <div className={styles.globalCommandsContainer} data-testid="GlobalCommands">
{actions.length === 1 ? ( {actions.length === 1 ? (
<Button icon={primaryAction.icon} onClick={onPrimaryActionClick} ref={primaryFocusableRef}> <Button
data-testid={`GlobalCommands/Button:${primaryAction.label}`}
icon={primaryAction.icon}
onClick={onPrimaryActionClick}
ref={primaryFocusableRef}
>
{primaryAction.label} {primaryAction.label}
</Button> </Button>
) : ( ) : (
@@ -253,8 +258,12 @@ const GlobalCommands: React.FC<GlobalCommandsProps> = ({ explorer }) => {
{(triggerProps: MenuButtonProps) => ( {(triggerProps: MenuButtonProps) => (
<div ref={setGlobalCommandButton}> <div ref={setGlobalCommandButton}>
<SplitButton <SplitButton
data-testid={`GlobalCommands/Button:${primaryAction.label}`}
menuButton={{ ...triggerProps, "aria-label": "More commands" }} menuButton={{ ...triggerProps, "aria-label": "More commands" }}
primaryActionButton={{ onClick: onPrimaryActionClick, ref: primaryFocusableRef }} primaryActionButton={{
onClick: onPrimaryActionClick,
ref: primaryFocusableRef,
}}
className={styles.globalCommandsSplitButton} className={styles.globalCommandsSplitButton}
icon={primaryAction.icon} icon={primaryAction.icon}
> >
@@ -376,7 +385,7 @@ export const SidebarContainer: React.FC<SidebarProps> = ({ explorer }) => {
{!isFabricNative() && ( {!isFabricNative() && (
<button <button
type="button" type="button"
data-test="Sidebar/RefreshButton" data-testid="Sidebar/RefreshButton"
className={styles.floatingControlButton} className={styles.floatingControlButton}
disabled={loading} disabled={loading}
title="Refresh" title="Refresh"

View File

@@ -2146,8 +2146,8 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
return ( return (
<CosmosFluentProvider className={styles.container}> <CosmosFluentProvider className={styles.container}>
<div data-test={"DocumentsTab"} className="tab-pane active" role="tabpanel" style={{ display: "flex" }}> <div data-testid={"DocumentsTab"} className="tab-pane active" role="tabpanel" style={{ display: "flex" }}>
<div data-test={"DocumentsTab/Filter"} className={`${styles.filterRow} ${styles.smallScreenContent}`}> <div data-testid={"DocumentsTab/Filter"} className={`${styles.filterRow} ${styles.smallScreenContent}`}>
{!isPreferredApiMongoDB && <span> SELECT * FROM c </span>} {!isPreferredApiMongoDB && <span> SELECT * FROM c </span>}
<InputDataList <InputDataList
dropdownOptions={getFilterChoices()} dropdownOptions={getFilterChoices()}
@@ -2164,7 +2164,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
/> />
<Button <Button
appearance="primary" appearance="primary"
data-test={"DocumentsTab/ApplyFilter"} data-testid={"DocumentsTab/ApplyFilter"}
size="small" size="small"
onClick={() => { onClick={() => {
if (isExecuting) { if (isExecuting) {
@@ -2191,7 +2191,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
> >
<Allotment.Pane preferredSize={`${tabStateData.leftPaneWidthPercent}%`} minSize={55}> <Allotment.Pane preferredSize={`${tabStateData.leftPaneWidthPercent}%`} minSize={55}>
<div <div
data-test={"DocumentsTab/DocumentsPane"} data-testid={"DocumentsTab/DocumentsPane"}
style={{ height: "100%", width: "100%", overflow: "hidden" }} style={{ height: "100%", width: "100%", overflow: "hidden" }}
ref={tableContainerRef} ref={tableContainerRef}
> >
@@ -2237,7 +2237,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
{tableItems.length > 0 && ( {tableItems.length > 0 && (
<a <a
className={styles.loadMore} className={styles.loadMore}
data-test={"DocumentsTab/LoadMore"} data-testid={"DocumentsTab/LoadMore"}
role="button" role="button"
tabIndex={0} tabIndex={0}
onClick={() => loadNextPage(documentsIterator.iterator, false)} onClick={() => loadNextPage(documentsIterator.iterator, false)}
@@ -2249,7 +2249,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
</div> </div>
</Allotment.Pane> </Allotment.Pane>
<Allotment.Pane minSize={30}> <Allotment.Pane minSize={30}>
<div data-test={"DocumentsTab/ResultsPane"} style={{ height: "100%", width: "100%" }}> <div data-testid={"DocumentsTab/ResultsPane"} style={{ height: "100%", width: "100%" }}>
{isTabActive && selectedDocumentContent && selectedRows.size <= 1 && ( {isTabActive && selectedDocumentContent && selectedRows.size <= 1 && (
<EditorReact <EditorReact
language={"json"} language={"json"}

View File

@@ -6,7 +6,7 @@ exports[`Documents tab (noSql API) when rendered should render the page 1`] = `
> >
<div <div
className="tab-pane active" className="tab-pane active"
data-test="DocumentsTab" data-testid="DocumentsTab"
role="tabpanel" role="tabpanel"
style={ style={
{ {
@@ -16,7 +16,7 @@ exports[`Documents tab (noSql API) when rendered should render the page 1`] = `
> >
<div <div
className="___11ktxfv_0000000 f1o614cb fy9rknc f22iagw fsnqrgy f1f5gg8d fjodcmx f122n59 f1f09k3d fg706s2 frpde29 ___1ngl8o6_0000000 fz7mnu6 fl3egqs flhmrkm" className="___11ktxfv_0000000 f1o614cb fy9rknc f22iagw fsnqrgy f1f5gg8d fjodcmx f122n59 f1f09k3d fg706s2 frpde29 ___1ngl8o6_0000000 fz7mnu6 fl3egqs flhmrkm"
data-test="DocumentsTab/Filter" data-testid="DocumentsTab/Filter"
> >
<span> <span>
SELECT * FROM c SELECT * FROM c
@@ -51,7 +51,7 @@ exports[`Documents tab (noSql API) when rendered should render the page 1`] = `
<Button <Button
appearance="primary" appearance="primary"
aria-label="Apply filter" aria-label="Apply filter"
data-test="DocumentsTab/ApplyFilter" data-testid="DocumentsTab/ApplyFilter"
disabled={false} disabled={false}
onClick={[Function]} onClick={[Function]}
size="small" size="small"
@@ -68,7 +68,7 @@ exports[`Documents tab (noSql API) when rendered should render the page 1`] = `
preferredSize="35%" preferredSize="35%"
> >
<div <div
data-test="DocumentsTab/DocumentsPane" data-testid="DocumentsTab/DocumentsPane"
style={ style={
{ {
"height": "100%", "height": "100%",
@@ -130,7 +130,7 @@ exports[`Documents tab (noSql API) when rendered should render the page 1`] = `
minSize={30} minSize={30}
> >
<div <div
data-test="DocumentsTab/ResultsPane" data-testid="DocumentsTab/ResultsPane"
style={ style={
{ {
"height": "100%", "height": "100%",

View File

@@ -116,7 +116,7 @@ export const ErrorList: React.FC<{ errors: QueryError[] }> = ({ errors }) => {
return ( return (
<DataGrid <DataGrid
data-test="QueryTab/ResultsPane/ErrorList" data-testid="QueryTab/ResultsPane/ErrorList"
items={errors} items={errors}
columns={columns} columns={columns}
sortable sortable
@@ -131,9 +131,9 @@ export const ErrorList: React.FC<{ errors: QueryError[] }> = ({ errors }) => {
</DataGridHeader> </DataGridHeader>
<DataGridBody<QueryError>> <DataGridBody<QueryError>>
{({ item, rowId }) => ( {({ item, rowId }) => (
<DataGridRow<QueryError> key={rowId} data-test={`Row:${rowId}`}> <DataGridRow<QueryError> key={rowId} data-testid={`Row:${rowId}`}>
{({ columnId, renderCell }) => ( {({ columnId, renderCell }) => (
<DataGridCell data-test={`Row:${rowId}/Column:${columnId}`}>{renderCell(item)}</DataGridCell> <DataGridCell data-testid={`Row:${rowId}/Column:${columnId}`}>{renderCell(item)}</DataGridCell>
)} )}
</DataGridRow> </DataGridRow>
)} )}

View File

@@ -3,13 +3,13 @@ import QueryError from "Common/QueryError";
import { IndeterminateProgressBar } from "Explorer/Controls/IndeterminateProgressBar"; import { IndeterminateProgressBar } from "Explorer/Controls/IndeterminateProgressBar";
import { MessageBanner } from "Explorer/Controls/MessageBanner"; import { MessageBanner } from "Explorer/Controls/MessageBanner";
import { useQueryTabStyles } from "Explorer/Tabs/QueryTab/Styles"; import { useQueryTabStyles } from "Explorer/Tabs/QueryTab/Styles";
import useZoomLevel from "hooks/useZoomLevel";
import React from "react"; import React from "react";
import { conditionalClass } from "Utils/StyleUtils";
import RunQuery from "../../../../images/RunQuery.png"; import RunQuery from "../../../../images/RunQuery.png";
import { QueryResults } from "../../../Contracts/ViewModels"; import { QueryResults } from "../../../Contracts/ViewModels";
import { ErrorList } from "./ErrorList"; import { ErrorList } from "./ErrorList";
import { ResultsView } from "./ResultsView"; import { ResultsView } from "./ResultsView";
import useZoomLevel from "hooks/useZoomLevel";
import { conditionalClass } from "Utils/StyleUtils";
export interface ResultsViewProps { export interface ResultsViewProps {
isMongoDB: boolean; isMongoDB: boolean;
@@ -27,7 +27,7 @@ const ExecuteQueryCallToAction: React.FC = () => {
const styles = useQueryTabStyles(); const styles = useQueryTabStyles();
const isZoomed = useZoomLevel(); const isZoomed = useZoomLevel();
return ( return (
<div data-test="QueryTab/ResultsPane/ExecuteCTA" className={styles.executeCallToAction}> <div data-testid="QueryTab/ResultsPane/ExecuteCTA" className={styles.executeCallToAction}>
<div> <div>
<p> <p>
<img <img
@@ -54,7 +54,7 @@ export const QueryResultSection: React.FC<QueryResultProps> = ({
const maybeSubQuery = queryEditorContent && /.*\(.*SELECT.*\)/i.test(queryEditorContent); const maybeSubQuery = queryEditorContent && /.*\(.*SELECT.*\)/i.test(queryEditorContent);
return ( return (
<div data-test="QueryTab/ResultsPane" className={styles.queryResultsPanel}> <div data-testid="QueryTab/ResultsPane" className={styles.queryResultsPanel}>
{isExecuting && <IndeterminateProgressBar />} {isExecuting && <IndeterminateProgressBar />}
<MessageBanner <MessageBanner
messageId="QueryEditor.EmptyMongoQuery" messageId="QueryEditor.EmptyMongoQuery"

View File

@@ -64,7 +64,7 @@ describe("QueryTabComponent", () => {
const { container } = render(<QueryTabComponent {...propsMock} />); const { container } = render(<QueryTabComponent {...propsMock} />);
const launchCopilotButton = container.querySelector('[data-test="QueryTab/ResultsPane/ExecuteCTA"]'); const launchCopilotButton = container.querySelector('[data-testid="QueryTab/ResultsPane/ExecuteCTA"]');
fireEvent.keyDown(launchCopilotButton, { key: "c", altKey: true }); fireEvent.keyDown(launchCopilotButton, { key: "c", altKey: true });
expect(mockStore.setShowCopilotSidebar).toHaveBeenCalledWith(true); expect(mockStore.setShowCopilotSidebar).toHaveBeenCalledWith(true);

View File

@@ -746,7 +746,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
}} }}
> >
<Allotment.Pane <Allotment.Pane
data-test="QueryTab/EditorPane" data-testid="QueryTab/EditorPane"
preferredSize={ preferredSize={
this.state.queryViewSizePercent !== undefined ? `${this.state.queryViewSizePercent}%` : undefined this.state.queryViewSizePercent !== undefined ? `${this.state.queryViewSizePercent}%` : undefined
} }
@@ -813,7 +813,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
render(): JSX.Element { render(): JSX.Element {
const shouldScaleElements = this.state.showCopilotSidebar && this.isCopilotTabActive; const shouldScaleElements = this.state.showCopilotSidebar && this.isCopilotTabActive;
return ( return (
<div data-test="QueryTab" style={{ display: "flex", flexDirection: "row", height: "100%" }}> <div data-testid="QueryTab" style={{ display: "flex", flexDirection: "row", height: "100%" }}>
<div style={{ width: shouldScaleElements ? "70%" : "100%", height: "100%" }}> <div style={{ width: shouldScaleElements ? "70%" : "100%", height: "100%" }}>
{this.getEditorAndQueryResult()} {this.getEditorAndQueryResult()}
</div> </div>

View File

@@ -489,7 +489,7 @@ const QueryStatsTab: React.FC<Pick<ResultsViewProps, "queryResults">> = ({ query
return ( return (
<div className={styles.metricsGridContainer}> <div className={styles.metricsGridContainer}>
<DataGrid <DataGrid
data-test="QueryTab/ResultsPane/ResultsView/QueryStatsList" data-testid="QueryTab/ResultsPane/ResultsView/QueryStatsList"
className={styles.queryStatsGrid} className={styles.queryStatsGrid}
items={generateQueryStatsItems()} items={generateQueryStatsItems()}
columns={columns} columns={columns}
@@ -504,9 +504,9 @@ const QueryStatsTab: React.FC<Pick<ResultsViewProps, "queryResults">> = ({ query
</DataGridHeader> </DataGridHeader>
<DataGridBody<IDocument>> <DataGridBody<IDocument>>
{({ item, rowId }) => ( {({ item, rowId }) => (
<DataGridRow<IDocument> key={rowId} data-test={`Row:${rowId}`}> <DataGridRow<IDocument> key={rowId} data-testid={`Row:${rowId}`}>
{({ columnId, renderCell }) => ( {({ columnId, renderCell }) => (
<DataGridCell data-test={`Row:${rowId}/Column:${columnId}`}>{renderCell(item)}</DataGridCell> <DataGridCell data-testid={`Row:${rowId}/Column:${columnId}`}>{renderCell(item)}</DataGridCell>
)} )}
</DataGridRow> </DataGridRow>
)} )}
@@ -532,17 +532,17 @@ export const ResultsView: React.FC<ResultsViewProps> = ({ isMongoDB, queryResult
}, []); }, []);
return ( return (
<div data-test="QueryTab/ResultsPane/ResultsView" className={styles.queryResultsTabPanel}> <div data-testid="QueryTab/ResultsPane/ResultsView" className={styles.queryResultsTabPanel}>
<TabList selectedValue={activeTab} onTabSelect={onTabSelect}> <TabList selectedValue={activeTab} onTabSelect={onTabSelect}>
<Tab <Tab
data-test="QueryTab/ResultsPane/ResultsView/ResultsTab" data-testid="QueryTab/ResultsPane/ResultsView/ResultsTab"
id={ResultsTabs.Results} id={ResultsTabs.Results}
value={ResultsTabs.Results} value={ResultsTabs.Results}
> >
Results Results
</Tab> </Tab>
<Tab <Tab
data-test="QueryTab/ResultsPane/ResultsView/QueryStatsTab" data-testid="QueryTab/ResultsPane/ResultsView/QueryStatsTab"
id={ResultsTabs.QueryStats} id={ResultsTabs.QueryStats}
value={ResultsTabs.QueryStats} value={ResultsTabs.QueryStats}
> >

View File

@@ -237,14 +237,14 @@ function TabPane({ tab, active }: { tab: Tab; active: boolean }) {
if (tab) { if (tab) {
if ("render" in tab) { if ("render" in tab) {
return ( return (
<div data-test={`Tab:${tab.tabId}`} {...attrs}> <div data-testid={`Tab:${tab.tabId}`} {...attrs}>
{tab.render()} {tab.render()}
</div> </div>
); );
} }
} }
return <div data-test={`Tab:${tab.tabId}`} {...attrs} ref={ref} data-bind="html:html" />; return <div data-testid={`Tab:${tab.tabId}`} {...attrs} ref={ref} data-bind="html:html" />;
} }
const onKeyPressReactTab = (e: KeyboardEvent, tabKind: ReactTabKind): void => { const onKeyPressReactTab = (e: KeyboardEvent, tabKind: ReactTabKind): void => {

View File

@@ -129,7 +129,7 @@ const App: React.FunctionComponent = () => {
// Setting key is needed so React will re-render this element on any account change // Setting key is needed so React will re-render this element on any account change
key={databaseAccount?.id || encryptedTokenMetadata?.accountName || authType} key={databaseAccount?.id || encryptedTokenMetadata?.accountName || authType}
ref={ref} ref={ref}
data-test="DataExplorerFrame" data-testid="DataExplorerFrame"
id="explorerMenu" id="explorerMenu"
name="explorer" name="explorer"
className="iframe" className="iframe"

View File

@@ -103,7 +103,7 @@ const App: React.FunctionComponent = () => {
return ( return (
<KeyboardShortcutRoot> <KeyboardShortcutRoot>
<div className="flexContainer" aria-hidden="false" data-test="DataExplorerRoot"> <div className="flexContainer" aria-hidden="false" data-testid="DataExplorerRoot">
{userContext.features.enableContainerCopy && userContext.apiType === "SQL" ? ( {userContext.features.enableContainerCopy && userContext.apiType === "SQL" ? (
<ContainerCopyPanel explorer={explorer} /> <ContainerCopyPanel explorer={explorer} />
) : ( ) : (

View File

@@ -114,7 +114,7 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
<div id="connectWithAad"> <div id="connectWithAad">
<input className="filterbtnstyle" type="button" value="Sign In" onClick={login} /> <input className="filterbtnstyle" type="button" value="Sign In" onClick={login} />
{enableConnectionStringLogin && ( {enableConnectionStringLogin && (
<p className="switchConnectTypeText" data-test="Link:SwitchConnectionType" onClick={showForm}> <p className="switchConnectTypeText" data-testid="Link:SwitchConnectionType" onClick={showForm}>
Connect to your account with connection string Connect to your account with connection string
</p> </p>
)} )}

View File

@@ -463,7 +463,7 @@ export class SelfServeComponent extends React.Component<SelfServeComponentProps,
); );
} }
return ( return (
<div style={{ overflowX: "auto" }} data-test="DataExplorerRoot"> <div style={{ overflowX: "auto" }} data-testid="DataExplorerRoot">
<Stack tokens={containerStackTokens}> <Stack tokens={containerStackTokens}>
<Stack.Item> <Stack.Item>
<CommandBar styles={commandBarStyles} items={this.getCommandBarItems()} /> <CommandBar styles={commandBarStyles} items={this.getCommandBarItems()} />

View File

@@ -2,7 +2,7 @@
exports[`SelfServeComponent message bar and spinner snapshots 1`] = ` exports[`SelfServeComponent message bar and spinner snapshots 1`] = `
<div <div
data-test="DataExplorerRoot" data-testid="DataExplorerRoot"
style={ style={
{ {
"overflowX": "auto", "overflowX": "auto",
@@ -339,7 +339,7 @@ exports[`SelfServeComponent message bar and spinner snapshots 1`] = `
exports[`SelfServeComponent message bar and spinner snapshots 2`] = ` exports[`SelfServeComponent message bar and spinner snapshots 2`] = `
<div <div
data-test="DataExplorerRoot" data-testid="DataExplorerRoot"
style={ style={
{ {
"overflowX": "auto", "overflowX": "auto",
@@ -734,7 +734,7 @@ exports[`SelfServeComponent message bar and spinner snapshots 2`] = `
exports[`SelfServeComponent message bar and spinner snapshots 3`] = ` exports[`SelfServeComponent message bar and spinner snapshots 3`] = `
<div <div
data-test="DataExplorerRoot" data-testid="DataExplorerRoot"
style={ style={
{ {
"overflowX": "auto", "overflowX": "auto",
@@ -835,7 +835,7 @@ exports[`SelfServeComponent message bar and spinner snapshots 4`] = `
exports[`SelfServeComponent should render and honor save, discard, refresh actions 1`] = ` exports[`SelfServeComponent should render and honor save, discard, refresh actions 1`] = `
<div <div
data-test="DataExplorerRoot" data-testid="DataExplorerRoot"
style={ style={
{ {
"overflowX": "auto", "overflowX": "auto",

View File

@@ -1,50 +1,114 @@
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx"; import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx";
import {
deleteContainer,
deleteKeyspace,
openAndFillCreateCassandraTablePanel,
} from "../helpers/containerCreationHelpers";
test("Cassandra keyspace and table CRUD", async ({ page }) => { test("Cassandra: Keyspace and table CRUD", async ({ page }) => {
const keyspaceId = generateUniqueName("db"); const keyspaceId = generateUniqueName("keyspace");
const tableId = "testtable"; // A unique table name isn't needed because the keyspace is unique const tableId = generateUniqueName("table");
const explorer = await DataExplorer.open(page, TestAccount.Cassandra); const explorer = await DataExplorer.open(page, TestAccount.Cassandra);
await explorer.globalCommandButton("New Table").click(); // Create
await explorer.whilePanelOpen( await openAndFillCreateCassandraTablePanel(explorer, {
"Add Table", keyspaceId,
async (panel, okButton) => { tableId,
await panel.getByPlaceholder("Type a new keyspace id").fill(keyspaceId); isAutoscale: true,
await panel.getByPlaceholder("Enter table Id").fill(tableId); throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
await panel.getByTestId("autoscaleRUInput").fill(TEST_AUTOSCALE_THROUGHPUT_RU.toString()); });
await okButton.click();
}, const keyspaceNode = await explorer.waitForNode(keyspaceId);
{ closeTimeout: 5 * 60 * 1000 }, const tableNode = await explorer.waitForContainerNode(keyspaceId, tableId);
); await expect(tableNode.element).toBeAttached();
// Delete table
await deleteContainer(explorer, keyspaceId, tableId, "Delete Table");
await expect(tableNode.element).not.toBeAttached();
// Delete keyspace
await deleteKeyspace(explorer, keyspaceId);
await expect(keyspaceNode.element).not.toBeAttached();
});
test("Cassandra: New keyspace shared throughput", async ({ page }) => {
const keyspaceId = generateUniqueName("keyspace");
const tableId = generateUniqueName("table");
const explorer = await DataExplorer.open(page, TestAccount.Cassandra);
await openAndFillCreateCassandraTablePanel(explorer, {
keyspaceId,
tableId,
useSharedThroughput: true,
});
const keyspaceNode = await explorer.waitForNode(keyspaceId); const keyspaceNode = await explorer.waitForNode(keyspaceId);
const tableNode = await explorer.waitForContainerNode(keyspaceId, tableId); const tableNode = await explorer.waitForContainerNode(keyspaceId, tableId);
await tableNode.openContextMenu(); await expect(tableNode.element).toBeAttached();
await tableNode.contextMenuItem("Delete Table").click();
await explorer.whilePanelOpen(
"Delete Table",
async (panel, okButton) => {
await panel.getByRole("textbox", { name: "Confirm by typing the table id" }).fill(tableId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
await expect(tableNode.element).not.toBeAttached();
await keyspaceNode.openContextMenu();
await keyspaceNode.contextMenuItem("Delete Keyspace").click();
await explorer.whilePanelOpen(
"Delete Keyspace",
async (panel, okButton) => {
await panel.getByRole("textbox", { name: "Confirm by typing the Keyspace id" }).fill(keyspaceId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
// Cleanup
await deleteKeyspace(explorer, keyspaceId);
await expect(keyspaceNode.element).not.toBeAttached();
});
test("Cassandra: Manual throughput", async ({ page }) => {
const keyspaceId = generateUniqueName("keyspace");
const tableId = generateUniqueName("table");
const manualThroughput = 400;
const explorer = await DataExplorer.open(page, TestAccount.Cassandra);
await openAndFillCreateCassandraTablePanel(explorer, {
keyspaceId,
tableId,
isAutoscale: false,
throughputValue: manualThroughput,
});
const keyspaceNode = await explorer.waitForNode(keyspaceId);
const tableNode = await explorer.waitForContainerNode(keyspaceId, tableId);
await expect(tableNode.element).toBeAttached();
// Cleanup
await deleteKeyspace(explorer, keyspaceId);
await expect(keyspaceNode.element).not.toBeAttached();
});
test("Cassandra: Multiple tables in keyspace", async ({ page }) => {
const keyspaceId = generateUniqueName("keyspace");
const table1Id = generateUniqueName("table");
const table2Id = generateUniqueName("table");
const explorer = await DataExplorer.open(page, TestAccount.Cassandra);
// Create first table
await openAndFillCreateCassandraTablePanel(explorer, {
keyspaceId,
tableId: table1Id,
isAutoscale: true,
throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
});
const keyspaceNode = await explorer.waitForNode(keyspaceId);
await explorer.waitForContainerNode(keyspaceId, table1Id);
// Create second table in same keyspace
await openAndFillCreateCassandraTablePanel(explorer, {
keyspaceId,
tableId: table2Id,
isAutoscale: true,
throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
});
await explorer.waitForContainerNode(keyspaceId, table2Id);
// Cleanup
await deleteKeyspace(explorer, keyspaceId);
await expect(keyspaceNode.element).not.toBeAttached(); await expect(keyspaceNode.element).not.toBeAttached();
}); });

View File

@@ -344,7 +344,7 @@ export class DataExplorer {
* There's only a single "primary" button, but we still require you to pass the label to confirm you're selecting the right button. * There's only a single "primary" button, but we still require you to pass the label to confirm you're selecting the right button.
*/ */
globalCommandButton(label: string): Locator { globalCommandButton(label: string): Locator {
return this.frame.getByTestId("GlobalCommands").getByText(label); return this.frame.getByTestId(`GlobalCommands/Button:${label}`);
} }
/** Select the command bar button with the specified label */ /** Select the command bar button with the specified label */

View File

@@ -1,22 +1,108 @@
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx"; import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx";
import {
GREMLIN_CONFIG,
deleteContainer,
deleteDatabase,
openAndFillCreateContainerPanel,
} from "../helpers/containerCreationHelpers";
test("Gremlin graph CRUD", async ({ page }) => { test("Gremlin: Database and graph CRUD", async ({ page }) => {
const databaseId = generateUniqueName("db"); const databaseId = generateUniqueName("db");
const graphId = "testgraph"; // A unique graph name isn't needed because the database is unique const graphId = generateUniqueName("graph");
const explorer = await DataExplorer.open(page, TestAccount.Gremlin);
// Create
await openAndFillCreateContainerPanel(explorer, GREMLIN_CONFIG, {
databaseId,
containerId: graphId,
partitionKey: "/pk",
isAutoscale: true,
throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
});
const databaseNode = await explorer.waitForNode(databaseId);
const graphNode = await explorer.waitForContainerNode(databaseId, graphId);
await expect(graphNode.element).toBeAttached();
// Delete graph
await deleteContainer(explorer, databaseId, graphId, "Delete Graph");
await expect(graphNode.element).not.toBeAttached();
// Delete database
await deleteDatabase(explorer, databaseId);
await expect(databaseNode.element).not.toBeAttached();
});
test("Gremlin: New database shared throughput", async ({ page }) => {
const databaseId = generateUniqueName("db");
const graphId = generateUniqueName("graph");
const explorer = await DataExplorer.open(page, TestAccount.Gremlin);
await openAndFillCreateContainerPanel(explorer, GREMLIN_CONFIG, {
databaseId,
containerId: graphId,
partitionKey: "/pk",
useSharedThroughput: true,
});
const databaseNode = await explorer.waitForNode(databaseId);
const graphNode = await explorer.waitForContainerNode(databaseId, graphId);
await expect(graphNode.element).toBeAttached();
// Cleanup
await deleteDatabase(explorer, databaseId);
await expect(databaseNode.element).not.toBeAttached();
});
test("Gremlin: Manual throughput", async ({ page }) => {
const databaseId = generateUniqueName("db");
const graphId = generateUniqueName("graph");
const manualThroughput = 400;
const explorer = await DataExplorer.open(page, TestAccount.Gremlin);
await openAndFillCreateContainerPanel(explorer, GREMLIN_CONFIG, {
databaseId,
containerId: graphId,
partitionKey: "/pk",
isAutoscale: false,
throughputValue: manualThroughput,
});
const databaseNode = await explorer.waitForNode(databaseId);
const graphNode = await explorer.waitForContainerNode(databaseId, graphId);
await expect(graphNode.element).toBeAttached();
// Cleanup
await deleteDatabase(explorer, databaseId);
await expect(databaseNode.element).not.toBeAttached();
});
test("Gremlin: No unique keys support", async ({ page }) => {
const databaseId = generateUniqueName("db");
const graphId = generateUniqueName("graph");
const explorer = await DataExplorer.open(page, TestAccount.Gremlin); const explorer = await DataExplorer.open(page, TestAccount.Gremlin);
// Create new database and graph
await explorer.globalCommandButton("New Graph").click(); await explorer.globalCommandButton("New Graph").click();
await explorer.whilePanelOpen( await explorer.whilePanelOpen(
"New Graph", "New Graph",
async (panel, okButton) => { async (panel, okButton) => {
await panel.getByPlaceholder("Type a new database id").fill(databaseId); await panel.getByTestId("AddCollectionPanel/DatabaseId").fill(databaseId);
await panel.getByRole("textbox", { name: "Graph id, Example Graph1" }).fill(graphId); await panel.getByTestId("AddCollectionPanel/CollectionId").fill(graphId);
await panel.getByRole("textbox", { name: "Partition key" }).fill("/pk"); await panel.getByRole("textbox", { name: "Partition key" }).fill("/pk");
await panel.getByTestId("autoscaleRUInput").fill(TEST_AUTOSCALE_THROUGHPUT_RU.toString()); await panel.getByTestId("ThroughputInput/AutoscaleRUInput").fill(TEST_AUTOSCALE_THROUGHPUT_RU.toString());
// Verify unique key button is not present (Gremlin-specific API limitation)
const uniqueKeyButton = panel.getByTestId("AddCollectionPanel/AddUniqueKeyButton");
await expect(uniqueKeyButton).not.toBeVisible();
await okButton.click(); await okButton.click();
}, },
{ closeTimeout: 5 * 60 * 1000 }, { closeTimeout: 5 * 60 * 1000 },
@@ -24,29 +110,9 @@ test("Gremlin graph CRUD", async ({ page }) => {
const databaseNode = await explorer.waitForNode(databaseId); const databaseNode = await explorer.waitForNode(databaseId);
const graphNode = await explorer.waitForContainerNode(databaseId, graphId); const graphNode = await explorer.waitForContainerNode(databaseId, graphId);
await expect(graphNode.element).toBeAttached();
await graphNode.openContextMenu(); // Cleanup
await graphNode.contextMenuItem("Delete Graph").click(); await deleteDatabase(explorer, databaseId);
await explorer.whilePanelOpen(
"Delete Graph",
async (panel, okButton) => {
await panel.getByRole("textbox", { name: "Confirm by typing the graph id" }).fill(graphId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
await expect(graphNode.element).not.toBeAttached();
await databaseNode.openContextMenu();
await databaseNode.contextMenuItem("Delete Database").click();
await explorer.whilePanelOpen(
"Delete Database",
async (panel, okButton) => {
await panel.getByRole("textbox", { name: "Confirm by typing the Database id" }).fill(databaseId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
await expect(databaseNode.element).not.toBeAttached(); await expect(databaseNode.element).not.toBeAttached();
}); });

View File

@@ -0,0 +1,323 @@
import { Locator } from "@playwright/test";
import { DataExplorer, TestAccount } from "../fx";
/**
* Container creation test API configuration
* Defines labels and selectors specific to each Cosmos DB API
*/
export interface ApiConfig {
account: TestAccount;
commandLabel: string; // "New Container", "New Collection", "New Graph", "New Table"
containerIdLabel: string; // "Container id", "Collection id", "Graph id", "Table id"
panelTitle: string; // "New Container", "New Collection", "New Graph", "Add Table"
databaseIdPlaceholder: string; // "Type a new keyspace id" for Cassandra, etc.
containerIdPlaceholder: string;
partitionKeyLabel?: string; // "Partition key", "Shard key", or undefined for Tables
partitionKeyPlaceholder?: string;
confirmDeleteLabel: string; // "Confirm by typing the [container/collection/table/graph] id"
databaseName?: string; // "TablesDB" for Tables, undefined for others
supportsUniqueKeys: boolean;
}
export const SQL_CONFIG: ApiConfig = {
account: TestAccount.SQL,
commandLabel: "New Container",
containerIdLabel: "Container id, Example Container1",
panelTitle: "New Container",
databaseIdPlaceholder: "Type a new database id",
containerIdPlaceholder: "e.g., Container1",
partitionKeyLabel: "Partition key",
partitionKeyPlaceholder: "/pk",
confirmDeleteLabel: "Confirm by typing the container id",
supportsUniqueKeys: true,
};
export const MONGO_CONFIG: ApiConfig = {
account: TestAccount.Mongo,
commandLabel: "New Collection",
containerIdLabel: "Collection id, Example Collection1",
panelTitle: "New Collection",
databaseIdPlaceholder: "Type a new database id",
containerIdPlaceholder: "e.g., Collection1",
partitionKeyLabel: "Shard key",
partitionKeyPlaceholder: "pk",
confirmDeleteLabel: "Confirm by typing the collection id",
supportsUniqueKeys: false,
};
export const MONGO32_CONFIG: ApiConfig = {
...MONGO_CONFIG,
account: TestAccount.Mongo32,
};
export const GREMLIN_CONFIG: ApiConfig = {
account: TestAccount.Gremlin,
commandLabel: "New Graph",
containerIdLabel: "Graph id, Example Graph1",
panelTitle: "New Graph",
databaseIdPlaceholder: "Type a new database id",
containerIdPlaceholder: "e.g., Graph1",
partitionKeyLabel: "Partition key",
partitionKeyPlaceholder: "/pk",
confirmDeleteLabel: "Confirm by typing the graph id",
supportsUniqueKeys: false,
};
export const TABLES_CONFIG: ApiConfig = {
account: TestAccount.Tables,
commandLabel: "New Table",
containerIdLabel: "Table id, Example Table1",
panelTitle: "New Table",
databaseIdPlaceholder: "", // Not used
containerIdPlaceholder: "e.g., Table1",
confirmDeleteLabel: "Confirm by typing the table id",
databaseName: "TablesDB",
supportsUniqueKeys: false,
};
export const CASSANDRA_CONFIG: ApiConfig = {
account: TestAccount.Cassandra,
commandLabel: "New Table",
containerIdLabel: "Enter table Id",
panelTitle: "Add Table",
databaseIdPlaceholder: "Type a new keyspace id",
containerIdPlaceholder: "Enter table Id",
confirmDeleteLabel: "Confirm by typing the table id",
supportsUniqueKeys: false,
};
/**
* Fills database selection in the panel
* Automatically selects "Create new" and fills the database ID
*/
export async function fillDatabaseSelection(panel: Locator, databaseId: string): Promise<void> {
// Wait for the radio button to be visible and click it (more reliable than check for custom styled radios)
await panel.getByTestId("AddCollectionPanel/DatabaseRadio:CreateNew").waitFor({ state: "visible" });
await panel.getByTestId("AddCollectionPanel/DatabaseRadio:CreateNew").click();
await panel.getByTestId("AddCollectionPanel/DatabaseId").fill(databaseId);
}
/**
* Fills existing database selection
* Selects "Use existing" and clicks the dropdown to select the database
*/
export async function fillExistingDatabaseSelection(panel: Locator, databaseId: string): Promise<void> {
await panel.getByTestId("AddCollectionPanel/DatabaseRadio:UseExisting").waitFor({ state: "visible" });
await panel.getByTestId("AddCollectionPanel/DatabaseRadio:UseExisting").click();
await panel.getByTestId("AddCollectionPanel/ExistingDatabaseDropdown").click();
await panel.locator(`text=${databaseId}`).click();
}
/**
* Fills container/collection/graph/table details
*/
export async function fillContainerDetails(
panel: Locator,
containerId: string,
partitionKey: string | undefined,
): Promise<void> {
await panel.getByTestId("AddCollectionPanel/CollectionId").fill(containerId);
if (partitionKey) {
await panel.getByTestId("AddCollectionPanel/PartitionKey").first().fill(partitionKey);
}
}
/**
* Fills Cassandra-specific table details
* (keyspace and table IDs are separate for Cassandra)
*/
export async function fillCassandraTableDetails(panel: Locator, keyspaceId: string, tableId: string): Promise<void> {
await panel.getByTestId("AddCollectionPanel/DatabaseId").fill(keyspaceId);
await panel.getByTestId("AddCollectionPanel/CollectionId").fill(tableId);
}
/**
* Sets throughput mode and value
* @param isAutoscale - if true, sets autoscale mode; if false, sets manual mode
*/
export async function setThroughput(panel: Locator, isAutoscale: boolean, throughputValue: number): Promise<void> {
const testId = isAutoscale ? "ThroughputInput/ThroughputMode:Autoscale" : "ThroughputInput/ThroughputMode:Manual";
await panel.getByTestId(testId).check();
if (isAutoscale) {
await panel.getByTestId("ThroughputInput/AutoscaleRUInput").fill(throughputValue.toString());
} else {
await panel.getByTestId("ThroughputInput/ManualThroughputInput").fill(throughputValue.toString());
}
}
/**
* Adds a unique key to the container (SQL/Mongo only)
*/
export async function addUniqueKey(panel: Locator, uniqueKeyValue: string): Promise<void> {
// Scroll to find the unique key section
await panel.getByTestId("AddCollectionPanel/UniqueKeysSection").scrollIntoViewIfNeeded();
// Click the "Add unique key" button
await panel.getByTestId("AddCollectionPanel/AddUniqueKeyButton").click();
// Fill in the unique key value
const uniqueKeyInput = panel.getByTestId("AddCollectionPanel/UniqueKey").first();
await uniqueKeyInput.fill(uniqueKeyValue);
}
/**
* Deletes a database and waits for it to disappear from the tree
*/
export async function deleteDatabase(
explorer: DataExplorer,
databaseId: string,
databaseNodeName: string = databaseId,
): Promise<void> {
const databaseNode = await explorer.waitForNode(databaseNodeName);
await databaseNode.openContextMenu();
await databaseNode.contextMenuItem("Delete Database").click();
await explorer.whilePanelOpen(
"Delete Database",
async (panel: Locator, okButton: Locator) => {
await panel.getByTestId("DeleteDatabaseConfirmationPanel/ConfirmInput").fill(databaseId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
}
/**
* Deletes a keyspace (Cassandra only)
*/
export async function deleteKeyspace(explorer: DataExplorer, keyspaceId: string): Promise<void> {
const keyspaceNode = await explorer.waitForNode(keyspaceId);
await keyspaceNode.openContextMenu();
await keyspaceNode.contextMenuItem("Delete Keyspace").click();
await explorer.whilePanelOpen(
"Delete Keyspace",
async (panel: Locator, okButton: Locator) => {
await panel.getByTestId("DeleteCollectionConfirmationPane/ConfirmInput").fill(keyspaceId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
}
/**
* Deletes a container/collection/graph/table
*/
export async function deleteContainer(
explorer: DataExplorer,
databaseId: string,
containerId: string,
deleteLabel: string, // "Delete Container", "Delete Collection", etc.
): Promise<void> {
const containerNode = await explorer.waitForContainerNode(databaseId, containerId);
await containerNode.openContextMenu();
await containerNode.contextMenuItem(deleteLabel).click();
await explorer.whilePanelOpen(
deleteLabel,
async (panel: Locator, okButton: Locator) => {
// All container/collection/graph/table deletes use same panel with test ID
await panel.getByTestId("DeleteCollectionConfirmationPane/ConfirmInput").fill(containerId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
}
/**
* Opens the create container dialog and fills in the form based on scenario
*/
export async function openAndFillCreateContainerPanel(
explorer: DataExplorer,
config: ApiConfig,
options: {
databaseId: string;
containerId: string;
partitionKey?: string;
useExistingDatabase?: boolean;
isAutoscale?: boolean;
throughputValue?: number;
uniqueKey?: string;
useSharedThroughput?: boolean;
},
): Promise<void> {
await explorer.globalCommandButton(config.commandLabel).click();
await explorer.whilePanelOpen(
config.panelTitle,
async (panel, okButton) => {
// Database selection
if (options.useExistingDatabase) {
await fillExistingDatabaseSelection(panel, options.databaseId);
} else {
await fillDatabaseSelection(panel, options.databaseId);
}
// Shared throughput checkbox (if applicable)
if (options.useSharedThroughput) {
await panel
.getByTestId("AddCollectionPanel/SharedThroughputCheckbox")
.getByRole("checkbox")
.check({ force: true });
}
// Container details
await fillContainerDetails(panel, options.containerId, options.partitionKey);
// Throughput (only if not using shared throughput)
if (!options.useSharedThroughput) {
const isAutoscale = options.isAutoscale !== false;
const throughputValue = options.throughputValue || 1000;
await setThroughput(panel, isAutoscale, throughputValue);
}
// Unique keys (if applicable)
if (options.uniqueKey && config.supportsUniqueKeys) {
await addUniqueKey(panel, options.uniqueKey);
}
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
}
/**
* Opens the create table dialog for Cassandra and fills in the form
* Cassandra has a different UI pattern than other APIs
*/
export async function openAndFillCreateCassandraTablePanel(
explorer: DataExplorer,
options: {
keyspaceId: string;
tableId: string;
isAutoscale?: boolean;
throughputValue?: number;
useSharedThroughput?: boolean;
},
): Promise<void> {
await explorer.globalCommandButton("New Table").click();
await explorer.whilePanelOpen(
"Add Table",
async (panel, okButton) => {
// Fill Cassandra-specific table details
await fillCassandraTableDetails(panel, options.keyspaceId, options.tableId);
// Shared throughput checkbox (if applicable)
if (options.useSharedThroughput) {
await panel
.getByTestId("AddCollectionPanel/SharedThroughputCheckbox")
.getByRole("checkbox")
.check({ force: true });
}
// Throughput (only if not using shared throughput)
if (!options.useSharedThroughput) {
const isAutoscale = options.isAutoscale !== false;
const throughputValue = options.throughputValue || 1000;
await setThroughput(panel, isAutoscale, throughputValue);
}
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
}

View File

@@ -1,58 +1,118 @@
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx"; import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx";
import {
MONGO32_CONFIG,
MONGO_CONFIG,
deleteContainer,
deleteDatabase,
openAndFillCreateContainerPanel,
} from "../helpers/containerCreationHelpers";
( (
[ [
["latest API version", TestAccount.Mongo], ["latest API version", MONGO_CONFIG],
["3.2 API", TestAccount.Mongo32], ["3.2 API", MONGO32_CONFIG],
] as [string, TestAccount][] ] as [string, typeof MONGO_CONFIG][]
).forEach(([apiVersionDescription, accountType]) => { ).forEach(([apiVersionDescription, config]) => {
test(`Mongo CRUD using ${apiVersionDescription}`, async ({ page }) => { test(`Mongo: Database and collection CRUD using ${apiVersionDescription}`, async ({ page }) => {
const databaseId = generateUniqueName("db"); const databaseId = generateUniqueName("db");
const collectionId = "testcollection"; // A unique collection name isn't needed because the database is unique const collectionId = generateUniqueName("collection");
const explorer = await DataExplorer.open(page, accountType); const explorer = await DataExplorer.open(page, config.account);
await explorer.globalCommandButton("New Collection").click(); // Create
await explorer.whilePanelOpen( await openAndFillCreateContainerPanel(explorer, config, {
"New Collection", databaseId,
async (panel, okButton) => { containerId: collectionId,
await panel.getByPlaceholder("Type a new database id").fill(databaseId); partitionKey: "pk",
await panel.getByRole("textbox", { name: "Collection id, Example Collection1" }).fill(collectionId); isAutoscale: true,
await panel.getByRole("textbox", { name: "Shard key" }).fill("pk"); throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
await panel.getByTestId("autoscaleRUInput").fill(TEST_AUTOSCALE_THROUGHPUT_RU.toString()); });
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
const databaseNode = await explorer.waitForNode(databaseId); const databaseNode = await explorer.waitForNode(databaseId);
const collectionNode = await explorer.waitForContainerNode(databaseId, collectionId); const collectionNode = await explorer.waitForContainerNode(databaseId, collectionId);
await expect(collectionNode.element).toBeAttached();
await collectionNode.openContextMenu(); // Delete collection
await collectionNode.contextMenuItem("Delete Collection").click(); await deleteContainer(explorer, databaseId, collectionId, "Delete Collection");
await explorer.whilePanelOpen(
"Delete Collection",
async (panel, okButton) => {
await panel.getByRole("textbox", { name: "Confirm by typing the collection id" }).fill(collectionId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
await expect(collectionNode.element).not.toBeAttached(); await expect(collectionNode.element).not.toBeAttached();
await databaseNode.openContextMenu(); // Delete database
await databaseNode.contextMenuItem("Delete Database").click(); await deleteDatabase(explorer, databaseId);
await explorer.whilePanelOpen(
"Delete Database",
async (panel, okButton) => {
await panel.getByRole("textbox", { name: "Confirm by typing the Database id" }).fill(databaseId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
await expect(databaseNode.element).not.toBeAttached(); await expect(databaseNode.element).not.toBeAttached();
}); });
}); });
test("Mongo: New database shared throughput", async ({ page }) => {
const databaseId = generateUniqueName("db");
const collectionId = generateUniqueName("collection");
const explorer = await DataExplorer.open(page, TestAccount.Mongo);
await openAndFillCreateContainerPanel(explorer, MONGO_CONFIG, {
databaseId,
containerId: collectionId,
partitionKey: "pk",
useSharedThroughput: true,
});
const databaseNode = await explorer.waitForNode(databaseId);
const collectionNode = await explorer.waitForContainerNode(databaseId, collectionId);
await expect(collectionNode.element).toBeAttached();
// Cleanup
await deleteDatabase(explorer, databaseId);
await expect(databaseNode.element).not.toBeAttached();
});
test("Mongo: Unique keys", async ({ page }) => {
const databaseId = generateUniqueName("db");
const collectionId = generateUniqueName("collection");
const explorer = await DataExplorer.open(page, TestAccount.Mongo);
await openAndFillCreateContainerPanel(explorer, MONGO_CONFIG, {
databaseId,
containerId: collectionId,
partitionKey: "pk",
isAutoscale: true,
throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
uniqueKey: "email",
});
const databaseNode = await explorer.waitForNode(databaseId);
const collectionNode = await explorer.waitForContainerNode(databaseId, collectionId);
await expect(collectionNode.element).toBeAttached();
// Cleanup
await deleteDatabase(explorer, databaseId);
await expect(databaseNode.element).not.toBeAttached();
});
test("Mongo: Manual throughput", async ({ page }) => {
const databaseId = generateUniqueName("db");
const collectionId = generateUniqueName("collection");
const manualThroughput = 400;
const explorer = await DataExplorer.open(page, TestAccount.Mongo);
await openAndFillCreateContainerPanel(explorer, MONGO_CONFIG, {
databaseId,
containerId: collectionId,
partitionKey: "pk",
isAutoscale: false,
throughputValue: manualThroughput,
});
const databaseNode = await explorer.waitForNode(databaseId);
const collectionNode = await explorer.waitForContainerNode(databaseId, collectionId);
await expect(collectionNode.element).toBeAttached();
// Cleanup
await deleteDatabase(explorer, databaseId);
await expect(databaseNode.element).not.toBeAttached();
});

View File

@@ -1,51 +1,110 @@
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx"; import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx";
import {
SQL_CONFIG,
deleteContainer,
deleteDatabase,
openAndFillCreateContainerPanel,
} from "../helpers/containerCreationHelpers";
test("SQL database and container CRUD", async ({ page }) => { test("SQL: Database and container CRUD", async ({ page }) => {
const databaseId = generateUniqueName("db"); const databaseId = generateUniqueName("db");
const containerId = "testcontainer"; // A unique container name isn't needed because the database is unique const containerId = generateUniqueName("container");
const explorer = await DataExplorer.open(page, TestAccount.SQL); const explorer = await DataExplorer.open(page, TestAccount.SQL);
await explorer.globalCommandButton("New Container").click(); // Create
await explorer.whilePanelOpen( await openAndFillCreateContainerPanel(explorer, SQL_CONFIG, {
"New Container", databaseId,
async (panel, okButton) => { containerId,
await panel.getByPlaceholder("Type a new database id").fill(databaseId); partitionKey: "/pk",
await panel.getByRole("textbox", { name: "Container id, Example Container1" }).fill(containerId); isAutoscale: true,
await panel.getByRole("textbox", { name: "Partition key" }).fill("/pk"); throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
await panel.getByTestId("autoscaleRUInput").fill(TEST_AUTOSCALE_THROUGHPUT_RU.toString()); });
await okButton.click();
}, const databaseNode = await explorer.waitForNode(databaseId);
{ closeTimeout: 5 * 60 * 1000 }, const containerNode = await explorer.waitForContainerNode(databaseId, containerId);
); await expect(containerNode.element).toBeAttached();
// Delete container
await deleteContainer(explorer, databaseId, containerId, "Delete Container");
await expect(containerNode.element).not.toBeAttached();
// Delete database
await deleteDatabase(explorer, databaseId);
await expect(databaseNode.element).not.toBeAttached();
});
test("SQL: New database shared throughput", async ({ page }) => {
const databaseId = generateUniqueName("db");
const containerId = generateUniqueName("container");
const explorer = await DataExplorer.open(page, TestAccount.SQL);
await openAndFillCreateContainerPanel(explorer, SQL_CONFIG, {
databaseId,
containerId,
partitionKey: "/pk",
useSharedThroughput: true,
});
const databaseNode = await explorer.waitForNode(databaseId); const databaseNode = await explorer.waitForNode(databaseId);
const containerNode = await explorer.waitForContainerNode(databaseId, containerId); const containerNode = await explorer.waitForContainerNode(databaseId, containerId);
await containerNode.openContextMenu(); await expect(containerNode.element).toBeAttached();
await containerNode.contextMenuItem("Delete Container").click();
await explorer.whilePanelOpen(
"Delete Container",
async (panel, okButton) => {
await panel.getByRole("textbox", { name: "Confirm by typing the container id" }).fill(containerId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
await expect(containerNode.element).not.toBeAttached();
await databaseNode.openContextMenu();
await databaseNode.contextMenuItem("Delete Database").click();
await explorer.whilePanelOpen(
"Delete Database",
async (panel, okButton) => {
await panel.getByRole("textbox", { name: "Confirm by typing the database id" }).fill(databaseId);
await okButton.click();
},
{ closeTimeout: 5 * 60 * 1000 },
);
// Cleanup
await deleteDatabase(explorer, databaseId);
await expect(databaseNode.element).not.toBeAttached();
});
test("SQL: Unique keys", async ({ page }) => {
const databaseId = generateUniqueName("db");
const containerId = generateUniqueName("container");
const explorer = await DataExplorer.open(page, TestAccount.SQL);
await openAndFillCreateContainerPanel(explorer, SQL_CONFIG, {
databaseId,
containerId,
partitionKey: "/pk",
isAutoscale: true,
throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
uniqueKey: "/email,/username",
});
const databaseNode = await explorer.waitForNode(databaseId);
const containerNode = await explorer.waitForContainerNode(databaseId, containerId);
await expect(containerNode.element).toBeAttached();
// Cleanup
await deleteDatabase(explorer, databaseId);
await expect(databaseNode.element).not.toBeAttached();
});
test("SQL: Manual throughput", async ({ page }) => {
const databaseId = generateUniqueName("db");
const containerId = generateUniqueName("container");
const manualThroughput = 400;
const explorer = await DataExplorer.open(page, TestAccount.SQL);
await openAndFillCreateContainerPanel(explorer, SQL_CONFIG, {
databaseId,
containerId,
partitionKey: "/pk",
isAutoscale: false,
throughputValue: manualThroughput,
});
const databaseNode = await explorer.waitForNode(databaseId);
const containerNode = await explorer.waitForContainerNode(databaseId, containerId);
await expect(containerNode.element).toBeAttached();
// Cleanup
await deleteDatabase(explorer, databaseId);
await expect(databaseNode.element).not.toBeAttached(); await expect(databaseNode.element).not.toBeAttached();
}); });

View File

@@ -1,35 +1,116 @@
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx"; import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx";
import { TABLES_CONFIG, deleteContainer, openAndFillCreateContainerPanel } from "../helpers/containerCreationHelpers";
test("Tables CRUD", async ({ page }) => { test("Tables: CRUD", async ({ page }) => {
const tableId = generateUniqueName("table"); // A unique table name IS needed because the database is shared when using Table Storage. const tableId = generateUniqueName("table");
const explorer = await DataExplorer.open(page, TestAccount.Tables); const explorer = await DataExplorer.open(page, TestAccount.Tables);
await explorer.globalCommandButton("New Table").click(); // Create
await explorer.whilePanelOpen( await openAndFillCreateContainerPanel(explorer, TABLES_CONFIG, {
"New Table", databaseId: "TablesDB",
async (panel, okButton) => { containerId: tableId,
await panel.getByRole("textbox", { name: "Table id, Example Table1" }).fill(tableId); isAutoscale: true,
await panel.getByTestId("autoscaleRUInput").fill(TEST_AUTOSCALE_THROUGHPUT_RU.toString()); throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
await okButton.click(); });
},
{ closeTimeout: 5 * 60 * 1000 },
);
const tableNode = await explorer.waitForContainerNode("TablesDB", tableId); const tableNode = await explorer.waitForContainerNode("TablesDB", tableId);
await expect(tableNode.element).toBeAttached();
await tableNode.openContextMenu(); // Delete table
await tableNode.contextMenuItem("Delete Table").click(); await deleteContainer(explorer, "TablesDB", tableId, "Delete Table");
await explorer.whilePanelOpen( await expect(tableNode.element).not.toBeAttached();
"Delete Table", });
async (panel, okButton) => {
await panel.getByRole("textbox", { name: "Confirm by typing the table id" }).fill(tableId); test("Tables: New database shared throughput", async ({ page }) => {
await okButton.click(); const tableId = generateUniqueName("table");
},
{ closeTimeout: 5 * 60 * 1000 }, const explorer = await DataExplorer.open(page, TestAccount.Tables);
);
await openAndFillCreateContainerPanel(explorer, TABLES_CONFIG, {
databaseId: "TablesDB",
containerId: tableId,
useSharedThroughput: true,
});
const tableNode = await explorer.waitForContainerNode("TablesDB", tableId);
await expect(tableNode.element).toBeAttached();
// Cleanup
await deleteContainer(explorer, "TablesDB", tableId, "Delete Table");
await expect(tableNode.element).not.toBeAttached();
});
test("Tables: Manual throughput", async ({ page }) => {
const tableId = generateUniqueName("table");
const manualThroughput = 400;
const explorer = await DataExplorer.open(page, TestAccount.Tables);
await openAndFillCreateContainerPanel(explorer, TABLES_CONFIG, {
databaseId: "TablesDB",
containerId: tableId,
isAutoscale: false,
throughputValue: manualThroughput,
});
const tableNode = await explorer.waitForContainerNode("TablesDB", tableId);
await expect(tableNode.element).toBeAttached();
// Cleanup
await deleteContainer(explorer, "TablesDB", tableId, "Delete Table");
await expect(tableNode.element).not.toBeAttached();
});
test("Tables: Multiple tables in TablesDB", async ({ page }) => {
const table1Id = generateUniqueName("table");
const table2Id = generateUniqueName("table");
const explorer = await DataExplorer.open(page, TestAccount.Tables);
// Create first table
await openAndFillCreateContainerPanel(explorer, TABLES_CONFIG, {
databaseId: "TablesDB",
containerId: table1Id,
isAutoscale: true,
throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
});
await explorer.waitForContainerNode("TablesDB", table1Id);
// Create second table
await openAndFillCreateContainerPanel(explorer, TABLES_CONFIG, {
databaseId: "TablesDB",
containerId: table2Id,
isAutoscale: true,
throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
});
await explorer.waitForContainerNode("TablesDB", table2Id);
// Cleanup
await deleteContainer(explorer, "TablesDB", table1Id, "Delete Table");
await deleteContainer(explorer, "TablesDB", table2Id, "Delete Table");
});
test("Tables: No partition key support", async ({ page }) => {
const tableId = generateUniqueName("table");
const explorer = await DataExplorer.open(page, TestAccount.Tables);
await openAndFillCreateContainerPanel(explorer, TABLES_CONFIG, {
databaseId: "TablesDB",
containerId: tableId,
isAutoscale: true,
throughputValue: TEST_AUTOSCALE_THROUGHPUT_RU,
});
const tableNode = await explorer.waitForContainerNode("TablesDB", tableId);
await expect(tableNode.element).toBeAttached();
// Cleanup
await deleteContainer(explorer, "TablesDB", tableId, "Delete Table");
await expect(tableNode.element).not.toBeAttached(); await expect(tableNode.element).not.toBeAttached();
}); });

View File

@@ -134,7 +134,7 @@ const initTestExplorer = async (): Promise<void> => {
); );
iframe.id = "explorerMenu"; iframe.id = "explorerMenu";
iframe.name = "explorer"; iframe.name = "explorer";
iframe.setAttribute("data-test", "DataExplorerFrame"); iframe.setAttribute("data-testid", "DataExplorerFrame");
iframe.classList.add("iframe"); iframe.classList.add("iframe");
iframe.title = "explorer"; iframe.title = "explorer";
iframe.src = iframeSrc; // CodeQL [SM03712] Not used in production, only for testing purposes iframe.src = iframeSrc; // CodeQL [SM03712] Not used in production, only for testing purposes