Revert "Page Views table I18n Date Fix and React redesign Pt. 2"

This reverts commit c58f903dc0.

Reason for revert: This commit causes both a bug when reading a null
userAgent string, whole pageview box breaks, and also removes a hover
feature that was previously there. The original reason for this ticket
was to fix a translation bug, but ballooned to a larger scope.

CLOSES OREO-1647

Change-Id: I1dc2d138125b094d6825d2c93fc358cba3fd2fa7
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/291597
Reviewed-by: Bryant Larsen <blarsen@instructure.com>
QA-Review: Kwok Lam <klam@instructure.com>
Product-Review: Noah Rush <noah.rush@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
This commit is contained in:
Noah Rush 2022-05-13 18:06:37 +00:00
parent bf2a9d226c
commit bedcf89695
9 changed files with 94 additions and 846 deletions

View File

@ -16,8 +16,37 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
%>
<div id="pageviews" data-user-id="<%= @user.id %>" style="overflow-x:auto; overflow-y:hidden">
<div id="pageviews_datefilter">
<div class="nobr">
<label class="ic-Label" for="page_view_date"><%= t('Filter by date') %></label>
<input type="datetime" class="ic-Input" id="page_view_date"/>
</div>
</div>
<div id="pageviews">
<table data-user-id="<%= @user.id %>" class="ic-Table ic-Table--hover-row ic-Table--condensed ic-Table--striped">
<thead class='ui-widget-header'>
<tr>
<th><%= t('headers.url', "URL") %></th>
<th><%= t('headers.date', "Date") %></th>
<th><%= t('headers.participated', "Participated") %></th>
<th><%= t('headers.time', "Time") %></th>
<th>
<div style="float:<%= direction('right') %>; margin-<%= direction('right') %>: 4px">
<%= link_to(t('page views csv'),
user_page_views_path(@user, :format => :csv),
class: 'icon-ms-excel',
id: 'page_views_csv_link',
'aria-label' => t('Download Page Views CSV'))
%>
</div>
<%= t('headers.user_agent', "User Agent") %>
</th>
</tr>
</thead>
<tbody id="page_view_results">
</tbody>
</table>
</div>
<% css_bundle :page_views %>
<% js_bundle :page_views %>

View File

@ -58,26 +58,26 @@ describe "users" do
end
it "validates a basic page view" do
page_view(user: @student, course: @course, url: "assignments", user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36", http_method: "get")
page_view(user: @student, course: @course, url: "assignments")
get "/users/#{@student.id}"
rows = ff("#page_view_results tr")
expect(rows.count).to eq 1
page_view = rows.first
expect(page_view).to include_text("Chrome")
expect(page_view).to include_text("Firefox")
expect(page_view).to include_text("assignments")
expect(f("#page_view_results")).not_to contain_css("tr [name='IconCheckMark']") # should not have a participation
expect(f("#page_view_results")).not_to contain_css("tr img") # should not have a participation
end
it "validates page view with a participation" do
page_view(user: @student, course: @course, participated: true)
get "/users/#{@student.id}"
expect(f("#page_view_results [name='IconCheckMark']")).to be_displayed
expect(f("#page_view_results .icon-check")).to be_displayed
end
it "validates a page view url" do
second_student_name = "test student for page views"
get "/users/#{@student.id}"
page_view(user: @student, course: @course, participated: true, url: student_in_course(name: second_student_name).user.id.to_s, user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36", http_method: "get")
page_view(user: @student, course: @course, participated: true, url: student_in_course(name: second_student_name).user.id.to_s)
refresh_page # in order to get the generated page view
page_view_url = f("#page_view_results a")
second_student = User.where(name: second_student_name).first
@ -88,31 +88,31 @@ describe "users" do
end
it "validates all page views were loaded" do
page_views_count = 30
page_views_count = 100
page_views_count.times { |i| page_view(user: @student, course: @course, url: ("%03d" % i).to_s) }
get "/users/#{@student.id}"
wait_for_ajaximations
scroll_page_to_bottom
driver.execute_script("$('#scrollContainer').scrollTop($('#scrollContainer')[0].scrollHeight);")
wait_for(method: nil, timeout: 0.5) { f("#paginatedView-loading").displayed? }
driver.execute_script("$('#pageviews').scrollTop($('#pageviews')[0].scrollHeight);")
# wait for loading spinner to finish
wait_for(method: nil, timeout: 0.5) { f(".paginatedView-loading").displayed? }
wait_for_no_such_element { f(".paginatedView-loading") }
expect(ff("#page_view_results tr").length).to eq page_views_count
end
it "filters by date" do
old_date = DateTime.new(2022, 2, 10).beginning_of_day
page_view(user: @student, course: @course, url: "recent", created_at: old_date + 1.day + 2.hours)
page_view(user: @student, course: @course, url: "older", created_at: old_date + 1.hour)
old_date = 2.days.ago.beginning_of_day
page_view(user: @student, course: @course, url: "recent", created_at: 5.minutes.ago)
page_view(user: @student, course: @course, url: "older", created_at: old_date + 1.minute)
get "/users/#{@student.id}"
wait_for_ajaximations
expect(ff("#page_view_results tr").first.text).to include "recent"
replace_content(f("[data-testid='inputQueryDate']"), old_date.year.to_s + "-" + old_date.month.to_s + "-" + old_date.day.to_s)
replace_content(f("#page_view_date"), old_date.strftime("%Y-%m-%d"))
driver.action.send_keys(:tab).perform
wait_for_ajaximations
expect(ff("#page_view_results tr").first.text).to include "older"
match = f("#page_views_csv_link")["href"].match(/start_time=([^&]+)/)
expect(match[1]).to include old_date.year.to_s + "-0" + old_date.month.to_s
expect(DateTime.parse(match[1]).to_i).to eq old_date.to_i
end
end

View File

@ -42,7 +42,7 @@ module OtherHelperMethods
controller = opts[:controller] || "assignments"
summarized = opts[:summarized] || nil
url = opts[:url]
user_agent = opts[:user_agent] || "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"
user_agent = opts[:user_agent] || "firefox"
page_view = course.page_views.build(
user: user,
@ -54,7 +54,6 @@ module OtherHelperMethods
page_view.summarized = summarized
page_view.request_id = SecureRandom.hex(10)
page_view.created_at = opts[:created_at] || Time.now
page_view.http_method = opts[:http_method] || "get"
if opts[:participated]
page_view.participated = true

View File

@ -16,13 +16,57 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import $ from 'jquery'
import '@canvas/datetime'
import moment from 'moment'
import PageViewCollection from './backbone/collections/PageViewCollection'
import PageViewView from './backbone/views/PageViewView'
import ready from '@instructure/ready'
import React from 'react'
import ReactDOM from 'react-dom'
import {PageViews} from './react/PageViews'
function renderTable(date) {
const $container = $('#pageviews')
const $table = $container.find('table')
const userId = $table.attr('data-user-id')
const pageViews = new PageViewCollection()
pageViews.url = `/api/v1/users/${userId}/page_views`
const $csvLink = $('#page_views_csv_link')
let csvUrl = $csvLink.attr('href').split('?')[0]
if (date) {
const start_time = $.unfudgeDateForProfileTimezone(date)
const end_time = moment(start_time).add(1, 'days')
const date_params = `?start_time=${start_time.toISOString()}&end_time=${end_time.toISOString()}`
pageViews.url += date_params
csvUrl += date_params
}
$csvLink.attr('href', csvUrl)
const fetchOptions = {reset: true}
const pageViewsView = new PageViewView({
collection: pageViews,
el: $table,
fetchOptions
})
// Add events
pageViews.on('reset', pageViewsView.render, pageViewsView)
// Fetch page views
const fetchParams = {per_page: 100}
pageViewsView.$el.disableWhileLoading(pageViews.fetch({data: fetchParams}))
return pageViewsView
}
ready(() => {
const parentElement = document.getElementById('pageviews')
const userID = parentElement.getAttribute('data-user-id')
ReactDOM.render(<PageViews userID={userID} />, parentElement)
let view = renderTable()
$('#page_view_date')
.datetime_field({dateOnly: true})
.change(event => {
const date = $(event.target).data('date')
view.stopPaginationListener()
$('#page_view_results').empty()
view = renderTable(date)
})
})

View File

@ -1,118 +0,0 @@
/*
* Copyright (C) 2021 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import {TruncateText} from '@instructure/ui-truncate-text'
import {Text} from '@instructure/ui-text'
import {useScope as useI18nScope} from '@canvas/i18n'
import FriendlyDatetime from '@canvas/datetime/react/components/FriendlyDatetime'
import {IconCheckMarkSolid} from '@instructure/ui-icons'
import {Table} from '@instructure/ui-table'
import UAParser from 'ua-parser-js'
const I18n = useI18nScope('PageViews')
export default class PageViewRow extends React.Component {
static displayName = 'Row'
parseUserAgentString(userAgent) {
const SPEEDGRADER = 'SpeedGrader for iPad'
const parser = new UAParser(userAgent)
let browser = parser.getBrowser() ? parser.getBrowser().name : ''
if (userAgent.toLowerCase().indexOf('speedgrader') >= 0) {
browser = SPEEDGRADER
}
if (!browser) {
browser = I18n.t('browsers.unrecognized', 'Unrecognized Browser')
} else if (browser !== SPEEDGRADER) {
const version = parser.getBrowser().version ? parser.getBrowser().version.split('.')[0] : '0'
browser = `${browser} ${version}`
}
return browser
}
summarizedUserAgent(data) {
return data.app_name || this.parseUserAgentString(data.user_agent)
}
readableInteractionTime(data) {
const seconds = data.interaction_seconds
if (seconds > 5) {
return Math.round(seconds)
} else {
return '--'
}
}
urlAsLink(data) {
const method = data.http_method
const url = data.url || ''
if (!method || method !== 'get') return <>{url}</>
else
return (
<>
<a href={url}>{url}</a>
</>
)
}
particpatedIcon(data) {
if (data.participated) return <IconCheckMarkSolid />
else return <></>
}
renderRow() {
return (
<>
<Table.Row key={this.props.rowData.session_id}>
<Table.Cell key="url">
<Text key="url_text">
<TruncateText position="end">{this.urlAsLink(this.props.rowData)}</TruncateText>
</Text>
</Table.Cell>
<Table.Cell key="created_at">
<FriendlyDatetime
key="datetime"
dateTime={this.props.rowData.created_at}
showTime
format="%-d %b %Y %-l:%M%P"
/>
</Table.Cell>
<Table.Cell key="participated" textAlign="center">
<Text>{this.particpatedIcon(this.props.rowData)}</Text>
</Table.Cell>
<Table.Cell key="interaction_seconds" textAlign="center">
<Text>{this.readableInteractionTime(this.props.rowData)}</Text>
</Table.Cell>
<Table.Cell key="user_agent">
<Text>{this.summarizedUserAgent(this.props.rowData)}</Text>
</Table.Cell>
</Table.Row>
</>
)
}
render() {
if (this.props.rowData) return this.renderRow()
else return <></>
}
}

View File

@ -1,231 +0,0 @@
/*
* Copyright (C) 2021 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, {useState, useEffect, useCallback} from 'react'
import moment from 'moment'
import {useScope as useI18nScope} from '@canvas/i18n'
import {Alert} from '@instructure/ui-alerts'
import {Text} from '@instructure/ui-text'
import {Link} from '@instructure/ui-link'
import {Flex} from '@instructure/ui-flex'
import {ScreenReaderContent} from '@instructure/ui-a11y-content'
import {Spinner} from '@instructure/ui-spinner'
import {Table} from '@instructure/ui-table'
import tz from '@canvas/timezone'
import CanvasDateInput from '@canvas/datetime/react/components/DateInput'
import {unfudgeDateForProfileTimezone} from '@canvas/datetime/date-functions'
import doFetchApi from '@canvas/do-fetch-api-effect'
import InfiniteScroll from '@canvas/infinite-scroll'
import PageViewRow from './PageViewRow'
const I18n = useI18nScope('PageViews')
const SIZE = 50
export const PageViews = ({userID}) => {
const getCSVURL = useCallback(
date => {
const baseCSVURL = `/users/${userID}/page_views.csv`
return date
? baseCSVURL +
'?start_time=' +
unfudgeDateForProfileTimezone(date).toISOString() +
'&' +
'end_time=' +
moment(unfudgeDateForProfileTimezone(date)).add(1, 'days').toISOString()
: baseCSVURL
},
[userID]
)
const [jsonData, setPageViewResults] = useState([])
const [queryDate, updateQueryDate] = useState('')
const [error, setError] = useState('')
const [csvURLLink, setCSVURLLink] = useState(getCSVURL(''))
const [page, setPage] = useState('first')
const [nextPage, setNextPage] = useState('')
const [hasMore, setHasMore] = useState(false)
const [scrollContainer, setScrollContainer] = useState(null)
const formatDate = date => {
return tz.format(date, 'date.formats.medium')
}
useEffect(() => {
if (error)
<Alert
liveRegion={() => document.getElementById('aria_alerts')}
liveRegionPoliteness="assertive"
screenReaderOnly
>
{error}
</Alert>
}, [error])
useEffect(() => {
setCSVURLLink(getCSVURL(queryDate))
}, [getCSVURL, queryDate])
const onSuccessApi = data => {
if (data.link.next) {
setNextPage(data.link.next.page)
}
setPageViewResults(currentJsonData => {
setHasMore(data.json.length === SIZE)
return currentJsonData.concat(data.json)
})
}
useEffect(() => {
const params = {
start_time: `${queryDate ? unfudgeDateForProfileTimezone(queryDate).toISOString() : ''}`,
end_time: `${
queryDate
? moment(unfudgeDateForProfileTimezone(queryDate)).add(1, 'days').toISOString()
: ''
}`,
per_page: SIZE,
page
}
if (page === 'first') {
delete params.page
}
doFetchApi({
path: `/api/v1/users/${userID}/page_views`,
params
})
.then(onSuccessApi)
.catch(() => {
setError('Error Fetching PageViews')
})
}, [queryDate, page, userID])
const updateData = date => {
setPageViewResults([])
updateQueryDate(date)
setPage('first')
}
const loadMore = () => {
setPage(nextPage)
}
return (
<>
<div style={{overflowx: 'hidden', overflowy: 'hidden'}}>
<Flex
key="pageviews_datefilter"
direction="column"
margin="none none small"
align="start"
overflowY="hidden"
overflowX="hidden"
height="570px"
>
<Flex.Item
textAlign="start"
padding="xx-small"
height="50px"
overflowY="hidden"
overflowX="hidden"
>
<Text weight="bold">{I18n.t('Filter by date')}</Text>
</Flex.Item>
<Flex.Item
padding="x-small"
height="50px"
shouldShrink
overflowY="hidden"
overflowX="hidden"
>
<Flex overflowY="hidden" overflowX="hidden">
<Flex.Item>
<CanvasDateInput
dataTestid="inputQueryDate"
renderLabel={
<ScreenReaderContent>{I18n.t('Filter by date')}</ScreenReaderContent>
}
onSelectedDateChange={updateData}
formatDate={formatDate}
withRunningValue
/>
</Flex.Item>
<Flex.Item padding="x-small">
<Link id="page_views_csv_link" data-testid="page_views_csv_link" href={csvURLLink}>
{I18n.t('Download Page Views CSV')}
</Link>
</Flex.Item>
</Flex>
</Flex.Item>
<Flex.Item height="20px" />
<Flex.Item
key="page_views_table"
padding="x-small"
height="450px"
overflowY="auto"
id="scrollContainer"
data-testid="scrollContainer"
elementRef={setScrollContainer}
>
<InfiniteScroll
pageStart={0}
loadMore={loadMore}
hasMore={hasMore}
scrollContainer={scrollContainer}
loader={
<Spinner
id="paginatedView-loading"
renderTitle={I18n.t('Loading')}
size="small"
margin="0 0 0 medium"
/>
}
>
<Table layout="fixed" caption="Page View Results" user-id={userID}>
<Table.Head>
<Table.Row key="0">
<Table.ColHeader id="URL">
{I18n.t('#page_views.table.headers.url', 'URL')}
</Table.ColHeader>
<Table.ColHeader id="Date" width="175px">
{(I18n.t('#page_views.table.headers.date'), 'Date')}
</Table.ColHeader>
<Table.ColHeader id="Paticipated" width="115px" textAlign="start">
{(I18n.t('#page_views.table.headers.participated'), 'Participated')}
</Table.ColHeader>
<Table.ColHeader id="Time" width="60px" textAlign="start">
{(I18n.t('#page_views.table.headers.time'), 'Time')}
</Table.ColHeader>
<Table.ColHeader id="Agent" width="125px">
{(I18n.t('#page_views.table.headers.user_agent'), 'User Agent')}
</Table.ColHeader>
</Table.Row>
</Table.Head>
<Table.Body id="page_view_results">
{jsonData.map((element, index) => (
<PageViewRow displayName="Row" rowData={element} key={index.toString()} />
))}
</Table.Body>
</Table>
</InfiniteScroll>
</Flex.Item>
</Flex>
</div>
</>
)
}

View File

@ -1,81 +0,0 @@
/*
* Copyright (C) 2021 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import {mount} from 'enzyme'
import PageViewRow from '../PageViewRow'
const defaultData = (data = {}) => ({
action: 'show',
app_name: null,
asset_type: null,
asset_user_access_id: '12345',
context_type: 'Course',
contributed: false,
controller: 'assignments',
created_at: '2021-12-03T07:51:27Z',
developer_key_id: null,
http_method: 'get',
id: 'b45b74de-19fd-4178-b677-9957ec76b476',
interaction_seconds: null,
links: {user: 1, context: 1234, asset: null, real_user: null, account: 1},
participated: false,
remote_ip: '127.0.0.1',
render_time: 0.78121,
session_id: '58cb2c11111cd5a1b8a999fbe999ea',
summarized: null,
updated_at: '2021-12-03T07:51:27Z',
url: 'https://canvas.local/',
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36',
user_request: null,
...data
})
const EDGE_USER_AGENT =
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/12.246'
const CHROME_USER_AGENT =
'Mozilla/5.0 (X11; CrOS x86_64 8172.45.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.64'
const SAFARI_USER_AGENT =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9'
const SPEEDGRADER_USER_AGENT =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Speedgrader/1.3'
describe('user agents', () => {
it('edge', () => {
const wrapper = mount(<PageViewRow data={defaultData()} />)
expect(wrapper.instance().parseUserAgentString(EDGE_USER_AGENT)).toEqual('Edge 12')
})
it('chrome', () => {
const wrapper = mount(<PageViewRow data={defaultData()} />)
expect(wrapper.instance().parseUserAgentString(CHROME_USER_AGENT)).toEqual('Chrome 51')
})
it('safari', () => {
const wrapper = mount(<PageViewRow data={defaultData()} />)
expect(wrapper.instance().parseUserAgentString(SAFARI_USER_AGENT)).toEqual('Safari 9')
})
it('speedgrader', () => {
const wrapper = mount(<PageViewRow data={defaultData()} />)
expect(wrapper.instance().parseUserAgentString(SPEEDGRADER_USER_AGENT)).toEqual(
'SpeedGrader for iPad'
)
})
})

View File

@ -1,183 +0,0 @@
/*
* Copyright (C) 2021 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import {shallow} from 'enzyme'
import {render, fireEvent} from '@testing-library/react'
import fetchMock from 'fetch-mock'
import {PageViews} from '../PageViews'
import {act} from 'react-dom/test-utils'
import moment from 'moment'
import {unfudgeDateForProfileTimezone} from '@canvas/datetime/date-functions'
const processStartDate = date => {
const dateStr = unfudgeDateForProfileTimezone(date).toISOString()
return encodeURIComponent(dateStr)
}
const processEndDate = date => {
const dateStr = moment(unfudgeDateForProfileTimezone(date)).add(1, 'days').toISOString()
return encodeURIComponent(dateStr)
}
const defaultProps = (props = {}) => ({
userID: '718',
...props
})
const PATH_START = `/api/v1/users/718/page_views`
const DEFAULT_PATH = `${PATH_START}?start_time=&end_time=&per_page=50`
afterEach(() => {
fetchMock.restore()
})
it('renders correctly', () => {
const wrapper = shallow(<PageViews {...defaultProps()} />)
expect(wrapper).toMatchSnapshot()
})
it('Call api with error', () => {
const expectedDate = 'Jan 24, 2022'
const datePath = `${PATH_START}?start_time=${processStartDate(
expectedDate
)}&end_time=${processEndDate(expectedDate)}&per_page=50`
fetchMock.mock(DEFAULT_PATH, 500)
fetchMock.mock(datePath, {})
const {getByTestId} = render(<PageViews {...defaultProps()} />)
const inputDate = getByTestId('inputQueryDate')
fireEvent.change(inputDate, {target: {value: expectedDate}})
fireEvent.blur(inputDate)
expect(inputDate.value).toBe(expectedDate)
})
// it('Show table without data', () => {
// fetchMock.mock(DEFAULT_PATH, 200)
// const {queryAllByRole} = render(<PageViews {...defaultProps()} />)
// expect(queryAllByRole('row')).toHaveLength(1)
// })
it('Show data and load more data with scroll', async () => {
const defaultData = {
action: 'new',
app_name: null,
asset_type: null,
asset_user_access_id: null,
context_type: 'Course',
contributed: false,
controller: 'discussion_topics',
created_at: '2022-01-26T17:48:34Z',
developer_key_id: null,
http_method: 'get',
id: '32ea0daf-70ac-434e-9111-cf7c71d23df0',
interaction_seconds: 6,
links: {user: 893, context: 11, asset: null, real_user: 1, account: 2},
participated: true,
remote_ip: '::1',
render_time: 0.498169,
session_id: 'd268f88b12896612544921c836302c8e',
summarized: null,
updated_at: '2022-01-26T17:48:34Z',
url: null,
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36',
user_request: true
}
const page1 = Array(50)
.fill()
.map(index => {
const copy = {...defaultData}
copy.url = `url ${index}`
return copy
})
const page2 = Array(22)
.fill()
.map(index => {
const copy = {...defaultData}
copy.url = `url ${index}`
return copy
})
fetchMock.mock(DEFAULT_PATH, {
body: page1,
status: 200,
headers: {
Link: '<http://canvas.docker/api/v1/users/37/page_views?page=2>; rel="next"'
}
})
fetchMock.mock(`${DEFAULT_PATH}&page=2`, {
body: page2,
status: 200,
headers: {
Link: '<http://canvas.docker/api/v1/users/37/page_views?page=3>; rel="current"'
}
})
let wrapper
await act(async () => {
wrapper = render(<PageViews {...defaultProps()} />)
})
const {getByTestId, queryAllByRole} = wrapper
const scrollContainer = getByTestId('scrollContainer')
jest.spyOn(scrollContainer, 'scrollTop', 'get').mockImplementation(() => 450)
fireEvent.scroll(scrollContainer)
expect(queryAllByRole('row')).toHaveLength(73)
})
it('Select the input date and reset the input date', () => {
const expectedDate = 'Jan 27, 2021'
const datePath = `${PATH_START}?start_time=${processStartDate(
expectedDate
)}&end_time=${processEndDate(expectedDate)}&per_page=50`
fetchMock.mock(datePath, {})
fetchMock.mock(DEFAULT_PATH, {})
const {getByTestId} = render(<PageViews {...defaultProps()} />)
const inputDate = getByTestId('inputQueryDate')
fireEvent.change(inputDate, {target: {value: expectedDate}})
fireEvent.blur(inputDate)
expect(inputDate.value).toBe(expectedDate)
fireEvent.change(inputDate, {target: {value: ''}})
fireEvent.blur(inputDate)
expect(inputDate.value).toBe('')
})
it('Select date and download file', () => {
const expectedDate = 'Jan 27, 2022'
const {getByTestId} = render(<PageViews {...defaultProps()} />)
const inputDate = getByTestId('inputQueryDate')
fireEvent.change(inputDate, {target: {value: expectedDate}})
fireEvent.blur(inputDate)
expect(inputDate.value).toBe(expectedDate)
const pageViewLink = getByTestId('page_views_csv_link')
fireEvent.click(pageViewLink)
expect(pageViewLink).toBeInTheDocument()
})
it('Date with not result', () => {
const expectedDate = 'Jan 27, 2022'
const {getByTestId, queryAllByRole} = render(<PageViews {...defaultProps()} />)
const inputDate = getByTestId('inputQueryDate')
fireEvent.change(inputDate, {target: {value: expectedDate}})
fireEvent.blur(inputDate)
expect(inputDate.value).toBe(expectedDate)
expect(queryAllByRole('row')).toHaveLength(1)
})

View File

@ -1,211 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<Fragment>
<div
style={
Object {
"overflowx": "hidden",
"overflowy": "hidden",
}
}
>
<Flex
align="start"
as="span"
direction="column"
display="flex"
elementRef={[Function]}
height="570px"
justifyItems="start"
key="pageviews_datefilter"
margin="none none small"
overflowX="hidden"
overflowY="hidden"
withVisualDebug={false}
wrap="no-wrap"
>
<Item
as="span"
elementRef={[Function]}
height="50px"
overflowX="hidden"
overflowY="hidden"
padding="xx-small"
shouldGrow={false}
shouldShrink={false}
textAlign="start"
>
<Text
as="span"
letterSpacing="normal"
size="medium"
weight="bold"
wrap="normal"
>
Filter by date
</Text>
</Item>
<Item
as="span"
elementRef={[Function]}
height="50px"
overflowX="hidden"
overflowY="hidden"
padding="x-small"
shouldGrow={false}
shouldShrink={true}
>
<Flex
as="span"
direction="row"
display="flex"
elementRef={[Function]}
justifyItems="start"
overflowX="hidden"
overflowY="hidden"
withVisualDebug={false}
wrap="no-wrap"
>
<Item
as="span"
elementRef={[Function]}
shouldGrow={false}
shouldShrink={false}
>
<CanvasDateInput
dataTestid="inputQueryDate"
formatDate={[Function]}
onSelectedDateChange={[Function]}
renderLabel={
<ScreenReaderContent
as="span"
>
Filter by date
</ScreenReaderContent>
}
withRunningValue={true}
/>
</Item>
<Item
as="span"
elementRef={[Function]}
padding="x-small"
shouldGrow={false}
shouldShrink={false}
>
<Link
color="link"
data-testid="page_views_csv_link"
href="/users/718/page_views.csv"
iconPlacement="start"
id="page_views_csv_link"
isWithinText={true}
>
Download Page Views CSV
</Link>
</Item>
</Flex>
</Item>
<Item
as="span"
elementRef={[Function]}
height="20px"
shouldGrow={false}
shouldShrink={false}
/>
<Item
as="span"
data-testid="scrollContainer"
elementRef={[Function]}
height="450px"
id="scrollContainer"
key="page_views_table"
overflowY="auto"
padding="x-small"
shouldGrow={false}
shouldShrink={false}
>
<InfiniteScroll
hasMore={false}
loadMore={[Function]}
loader={
<Spinner
as="div"
id="paginatedView-loading"
margin="0 0 0 medium"
renderTitle="Loading"
size="small"
variant="default"
/>
}
pageStart={0}
scrollContainer={null}
threshold={250}
>
<Table
caption="Page View Results"
hover={false}
layout="fixed"
user-id="718"
>
<Head>
<Row
key="0"
>
<ColHeader
id="URL"
scope="col"
sortDirection="none"
textAlign="start"
>
URL
</ColHeader>
<ColHeader
id="Date"
scope="col"
sortDirection="none"
textAlign="start"
width="175px"
>
Date
</ColHeader>
<ColHeader
id="Paticipated"
scope="col"
sortDirection="none"
textAlign="start"
width="115px"
>
Participated
</ColHeader>
<ColHeader
id="Time"
scope="col"
sortDirection="none"
textAlign="start"
width="60px"
>
Time
</ColHeader>
<ColHeader
id="Agent"
scope="col"
sortDirection="none"
textAlign="start"
width="125px"
>
User Agent
</ColHeader>
</Row>
</Head>
<Body
id="page_view_results"
/>
</Table>
</InfiniteScroll>
</Item>
</Flex>
</div>
</Fragment>
`;