save slider tests

This commit is contained in:
Nate Kelley 2025-05-07 12:38:35 -06:00
parent 667ddb424e
commit 28c716c159
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
7 changed files with 150 additions and 37 deletions

View File

@ -0,0 +1,54 @@
import { test, expect } from '@playwright/test';
test('Invite User', async ({ page }) => {
await page.goto('http://localhost:3000/app/home');
await page
.locator('div')
.filter({ hasText: /^Invite people$/ })
.first()
.click();
await page.getByRole('textbox', { name: 'buster@bluthbananas.com,' }).click();
await page
.getByRole('textbox', { name: 'buster@bluthbananas.com,' })
.fill('nate+integration-test@buser.so');
await page.getByRole('button', { name: 'Send invites' }).click();
await page.waitForLoadState('networkidle');
await expect(page.getByText('Invites sent').first()).toBeVisible({ timeout: 3000 });
await page.getByRole('button').filter({ hasText: /^$/ }).first().click();
await page.getByRole('link', { name: 'Users' }).click();
await expect(page.getByRole('link', { name: 'nate+integration-test@buser.' })).toBeVisible();
await expect(page.getByRole('main')).toMatchAriaSnapshot(`
- img
- text: nate+integration-test@buser.so Restricted Querier
`);
await page.getByRole('link', { name: 'nate+integration-test@buser.' }).click();
await expect(page.getByText('nate+integration-test@buser.so')).toBeVisible();
});
test('Can change user role', async ({ page }) => {
await page.goto('http://localhost:3000/app/settings/users');
await page.getByRole('link', { name: 'B blake blake@buster.so' }).click();
await expect(page.getByText('blake@buster.so')).toBeVisible();
await expect(page.getByRole('combobox')).toHaveText(/Querier/);
await page.getByRole('combobox').click();
await page.getByRole('option', { name: 'Workspace Admin' }).click();
await expect(
page.locator('.text-text-secondary > div:nth-child(2) > .text-text-secondary').first()
).toBeVisible();
await page.waitForTimeout(25);
await page.waitForLoadState('networkidle');
await page.reload();
await expect(
page.locator('.text-text-secondary > div:nth-child(2) > .text-text-secondary').first()
).toBeVisible();
await page.getByRole('combobox').click();
await page.getByRole('option', { name: 'Querier', exact: true }).click();
await expect(
page.locator('.text-text-secondary > div:nth-child(2) > .text-text-secondary').first()
).toBeVisible();
await page.waitForTimeout(15);
await page.waitForLoadState('networkidle');
});

View File

@ -0,0 +1,49 @@
import { test, expect } from '@playwright/test';
test.describe.serial('Create a scatter plot with a question', () => {
const question = `I want to understand if there's a relationship between how much an employee sells and the number of orders they process. Can you generate a scatter plot showing each employee's total sales amount on one axis and their total number of orders on the other axis for the last 12 months?`;
let scatterURL = '';
test(`I can create a scatter plot with a question: ${question}`, async ({ page }) => {
await page.goto('http://localhost:3000/app/home');
await page.getByRole('textbox', { name: 'Ask Buster a question...' }).click();
await page.getByRole('textbox', { name: 'Ask Buster a question...' }).fill(question);
await page.getByRole('main').getByRole('button').click();
await page.waitForTimeout(5000);
await expect(page.getByRole('link', { name: 'Reasoning link' })).toBeVisible();
await expect(page.getByTestId('metric-view-chart-content').getByRole('img')).toBeVisible({
timeout: 240000
});
await expect(page.getByTestId('share-button')).toBeVisible();
await expect(page.getByTestId('save-to-dashboard-button')).toBeVisible();
await expect(page.getByTestId('edit-sql-button').getByRole('button')).toBeVisible();
await expect(page.getByTestId('edit-chart-button').getByRole('button')).toBeVisible();
await page.getByTestId('edit-chart-button').getByRole('button').click();
await expect(page.getByTestId('select-chart-type-scatter')).toBeVisible();
await expect(page.getByTestId('select-chart-type-scatter')).toHaveAttribute(
'data-state',
'selected'
);
const url = page.url();
await page.goto(
'http://localhost:3000/app/chats/21cd1170-7ecf-4796-9d5e-9828285c62ec/metrics/0023f1a3-58fe-53f7-9f23-07f20868e1b4/chart?secondary_view=chart-edit'
);
scatterURL = url;
});
scatterURL =
'http://localhost:3000/app/chats/21cd1170-7ecf-4796-9d5e-9828285c62ec/metrics/0023f1a3-58fe-53f7-9f23-07f20868e1b4/chart';
test(`I can update the scatter plot`, async ({ page }) => {
await page.goto(scatterURL);
await page.getByTestId('edit-chart-button').getByRole('button').click();
await expect(page.getByTestId('select-chart-type-scatter')).toBeVisible();
await expect(page.getByTestId('select-chart-type-scatter')).toHaveAttribute(
'data-state',
'selected'
);
await page.getByTestId('segmented-trigger-Styling').click();
//
});
});

View File

@ -166,13 +166,11 @@ export const prefetchGetUserList = async (
};
export const useInviteUser = () => {
const { openSuccessMessage } = useBusterNotifications();
const queryClient = useQueryClient();
return useMutation({
mutationFn: inviteUser,
onSuccess: () => {
openSuccessMessage('Invites sent');
const user = queryClient.getQueryData(queryKeys.userGetUserMyself.queryKey);
const teamId = user?.organizations?.[0]?.id;
if (teamId) {

View File

@ -73,6 +73,7 @@ ChartJS.register(
);
ChartJS.defaults.responsive = true;
ChartJS.defaults.clip = false;
ChartJS.defaults.resizeDelay = 7;
ChartJS.defaults.maintainAspectRatio = false;
ChartJS.defaults.color = color;
@ -85,11 +86,11 @@ ChartJS.defaults.font = {
};
[
ChartJS.defaults.scales.category,
(ChartJS.defaults.scales.category,
ChartJS.defaults.scales.linear,
ChartJS.defaults.scales.logarithmic,
ChartJS.defaults.scales.time,
ChartJS.defaults.scales.timeseries
ChartJS.defaults.scales.timeseries)
].forEach((scale) => {
scale.title = {
...scale.title,

View File

@ -10,6 +10,7 @@ import {
} from '@/components/ui/tooltip/TooltipBase';
import { cn } from '@/lib/utils';
import { ErrorBoundary } from '../error';
export interface SliderProps extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {
min?: number;
@ -34,8 +35,10 @@ const Slider = React.forwardRef<React.ElementRef<typeof SliderPrimitive.Root>, S
ref
) => {
const [useTooltip, setUseTooltip] = React.useState(false);
const [internalValues, setInternalValues] = React.useState(value || defaultValue || [min]);
const currentValue = value || defaultValue || [min];
const [internalValues, setInternalValues] = React.useState<number[]>(
value || defaultValue || [min]
);
const currentValue: number[] = value || defaultValue || [min];
const handleValueChange = React.useCallback(
(newValue: number[]) => {
@ -51,37 +54,41 @@ const Slider = React.forwardRef<React.ElementRef<typeof SliderPrimitive.Root>, S
setInternalValues(currentValue);
}, []);
return (
<SliderPrimitive.Root
ref={ref}
className={cn('relative flex w-full touch-none items-center select-none', className)}
min={min}
max={max}
step={step}
value={value}
defaultValue={defaultValue}
onValueChange={handleValueChange}
onValueCommit={handleValueCommit}
{...props}>
<SliderPrimitive.Track className="bg-primary/20 relative h-1.5 w-full grow overflow-hidden rounded-full">
<SliderPrimitive.Range className="bg-primary absolute h-full" />
</SliderPrimitive.Track>
console.log(internalValues, value, defaultValue, min);
<TooltipProvider>
<Tooltip open={useTooltip}>
<TooltipTrigger asChild>
<SliderPrimitive.Thumb
onMouseEnter={() => setUseTooltip(true)}
onMouseLeave={() => setUseTooltip(false)}
className="border-primary bg-background block h-4 w-4 cursor-pointer rounded-full border-2 shadow transition-all hover:scale-110 focus:outline-0 disabled:pointer-events-none disabled:opacity-50"
/>
</TooltipTrigger>
<TooltipContent side="top" sideOffset={5}>
{internalValues[0]}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</SliderPrimitive.Root>
return (
<ErrorBoundary errorComponent={<div>Error</div>}>
<SliderPrimitive.Root
ref={ref}
className={cn('relative flex w-full touch-none items-center select-none', className)}
min={min}
max={max}
step={step}
value={value}
defaultValue={internalValues}
onValueChange={handleValueChange}
onValueCommit={handleValueCommit}
{...props}>
<SliderPrimitive.Track className="bg-primary/20 relative h-1.5 w-full grow overflow-hidden rounded-full">
<SliderPrimitive.Range className="bg-primary absolute h-full" />
</SliderPrimitive.Track>
<TooltipProvider>
<Tooltip open={useTooltip}>
<TooltipTrigger asChild>
<SliderPrimitive.Thumb
onMouseEnter={() => setUseTooltip(true)}
onMouseLeave={() => setUseTooltip(false)}
className="border-primary bg-background block h-4 w-4 cursor-pointer rounded-full border-2 shadow transition-all hover:scale-110 focus:outline-0 disabled:pointer-events-none disabled:opacity-50"
/>
</TooltipTrigger>
<TooltipContent side="top" sideOffset={5}>
{internalValues[0]}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</SliderPrimitive.Root>
</ErrorBoundary>
);
}
);

View File

@ -18,14 +18,17 @@ export const EditScatterDotSize: React.FC<{
const newLower = v[0];
const newUpper = hasSize ? v[1] : newLower + 18;
const arrayFormat: [number, number] = [newLower, newUpper];
console.log({ arrayFormat });
onUpdateChartConfig({
scatterDotSize: arrayFormat
});
});
const arrayValue = Array.isArray(defaultValue) ? defaultValue : [defaultValue];
return (
<LabelAndInput label="Dot size">
<Slider min={1} max={50} step={1} value={defaultValue as number[]} onValueChange={onChange} />
<Slider min={1} max={50} step={1} value={arrayValue} onValueChange={onChange} />
</LabelAndInput>
);
});

View File

@ -146,6 +146,7 @@ const ChartButton: React.FC<{
disabled={disabled}
data-testid={`select-chart-type-${id}`}
onClick={() => !disabled && onSelectChartType(id)}
data-state={isSelected ? 'selected' : 'not-selected'}
className={cn(
'flex aspect-square h-[35px] w-full items-center justify-center hover:transition-none',
'hover:bg-item-hover cursor-pointer rounded',