Merge branch 'master' into sa-add-cors

pull/1173/head
Andrew Cravenho 6 years ago committed by GitHub
commit 3259b65388
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 80
      apps/block_scout_web/assets/__tests__/pages/address.js
  2. 124
      apps/block_scout_web/assets/__tests__/pages/address/transactions.js
  3. 1
      apps/block_scout_web/assets/js/app.js
  4. 59
      apps/block_scout_web/assets/js/pages/address.js
  5. 73
      apps/block_scout_web/assets/js/pages/address/transactions.js
  6. 22
      apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
  7. 36
      apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex
  8. 12
      apps/block_scout_web/priv/gettext/default.pot
  9. 12
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  10. 57
      apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs

@ -145,86 +145,36 @@ describe('RECEIVED_NEW_INTERNAL_TRANSACTION_BATCH', () => {
}) })
describe('RECEIVED_NEW_TRANSACTION', () => { describe('RECEIVED_NEW_TRANSACTION', () => {
test('with new transaction', () => { test('increment the transactions count', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
transactions: [{ transactionHash: 1, transactionHtml: 'test 1' }] addressHash: "0x001",
transactionCount: 1
}) })
const action = {
type: 'RECEIVED_NEW_TRANSACTION',
msg: { transactionHash: 2, transactionHtml: 'test 2' }
}
const output = reducer(state, action)
expect(output.transactions).toEqual([
{ transactionHash: 2, transactionHtml: 'test 2' },
{ transactionHash: 1, transactionHtml: 'test 1' }
])
})
test('when channel has been disconnected', () => {
const state = Object.assign({}, initialState, {
channelDisconnected: true,
transactions: [{ transactionHash: 1, transactionHtml: 'test 1' }]
})
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION', type: 'RECEIVED_NEW_TRANSACTION',
msg: { transactionHash: 2, transactionHtml: 'test 2' } msg: { fromAddressHash: "0x001", transactionHash: 2, transactionHtml: 'test 2' }
} }
const output = reducer(state, action)
expect(output.transactions).toEqual([ const newState = reducer(state, action)
{ transactionHash: 1, transactionHtml: 'test 1' }
])
})
test('beyond page one', () => {
const state = Object.assign({}, initialState, {
beyondPageOne: true,
transactions: [{ transactionHash: 1, transactionHtml: 'test 1' }]
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION',
msg: { transactionHash: 2, transactionHtml: 'test 2' }
}
const output = reducer(state, action)
expect(output.transactions).toEqual([ expect(newState.transactionCount).toEqual(2)
{ transactionHash: 1, transactionHtml: 'test 1' }
])
}) })
test('with filtered out transaction', () => {
test('does not increment the count if the channel is disconnected', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
filter: 'to' addressHash: "0x001",
transactionCount: 1,
channelDisconnected: true
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION', type: 'RECEIVED_NEW_TRANSACTION',
msg: { transactionHash: 2, transactionHtml: 'test 2' } msg: { fromAddressHash: "0x001", transactionHash: 2, transactionHtml: 'test 2' }
} }
const output = reducer(state, action)
expect(output.transactions).toEqual([])
})
})
describe('RECEIVED_NEXT_PAGE', () => { const newState = reducer(state, action)
test('with new transaction page', () => {
const state = Object.assign({}, initialState, {
loadingNextPage: true,
nextPageUrl: '1',
transactions: [{ transactionHash: 1, transactionHtml: 'test 1' }]
})
const action = {
type: 'RECEIVED_NEXT_PAGE',
msg: {
nextPageUrl: '2',
transactions: [{ transactionHash: 2, transactionHtml: 'test 2' }]
}
}
const output = reducer(state, action)
expect(output.loadingNextPage).toEqual(false) expect(newState.transactionCount).toEqual(1)
expect(output.nextPageUrl).toEqual('2')
expect(output.transactions).toEqual([
{ transactionHash: 1, transactionHtml: 'test 1' },
{ transactionHash: 2, transactionHtml: 'test 2' }
])
}) })
}) })

@ -0,0 +1,124 @@
import { reducer, initialState } from '../../../js/pages/address/transactions'
describe('RECEIVED_NEW_TRANSACTION', () => {
test('with new transaction', () => {
const state = Object.assign({}, initialState, {
items: ['transaction html']
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION',
msg: { transactionHtml: 'another transaction html' }
}
const output = reducer(state, action)
expect(output.items).toEqual([ 'another transaction html', 'transaction html' ])
})
test('when channel has been disconnected', () => {
const state = Object.assign({}, initialState, {
channelDisconnected: true,
items: ['transaction html']
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION',
msg: { transactionHtml: 'another transaction html' }
}
const output = reducer(state, action)
expect(output.items).toEqual(['transaction html'])
})
test('beyond page one', () => {
const state = Object.assign({}, initialState, {
beyondPageOne: true,
items: ['transaction html']
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION',
msg: { transactionHtml: 'another transaction html' }
}
const output = reducer(state, action)
expect(output.items).toEqual([ 'transaction html' ])
})
test('adds the new transaction to state even when it is filtered by to', () => {
const state = Object.assign({}, initialState, {
addressHash: '0x001',
filter: 'to',
items: []
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
fromAddressHash: '0x002',
transactionHtml: 'transaction html',
toAddressHash: '0x001'
}
}
const output = reducer(state, action)
expect(output.items).toEqual(['transaction html'])
})
test(
'does nothing when it is filtered by to but the toAddressHash is different from addressHash',
() => {
const state = Object.assign({}, initialState, {
addressHash: '0x001',
filter: 'to',
items: []
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
fromAddressHash: '0x003',
transactionHtml: 'transaction html',
toAddressHash: '0x002'
}
}
const output = reducer(state, action)
expect(output.items).toEqual([])
})
test('adds the new transaction to state even when it is filtered by from', () => {
const state = Object.assign({}, initialState, {
addressHash: '0x001',
filter: 'from',
items: []
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
fromAddressHash: '0x001',
transactionHtml: 'transaction html',
toAddressHash: '0x002'
}
}
const output = reducer(state, action)
expect(output.items).toEqual(['transaction html'])
})
test(
'does nothing when it is filtered by from but the fromAddressHash is different from addressHash',
() => {
const state = Object.assign({}, initialState, {
addressHash: '0x001',
filter: 'to',
items: []
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
addressHash: '0x001',
transactionHtml: 'transaction html',
fromAddressHash: '0x002'
}
}
const output = reducer(state, action)
expect(output.items).toEqual([])
})
})

@ -21,6 +21,7 @@ import 'bootstrap'
import './locale' import './locale'
import './pages/address' import './pages/address'
import './pages/address/transactions'
import './pages/address/validations' import './pages/address/validations'
import './pages/blocks' import './pages/blocks'
import './pages/chain' import './pages/chain'

@ -6,7 +6,6 @@ import numeral from 'numeral'
import socket from '../socket' import socket from '../socket'
import { createStore, connectElements } from '../lib/redux_helpers.js' import { createStore, connectElements } from '../lib/redux_helpers.js'
import { batchChannel } from '../lib/utils' import { batchChannel } from '../lib/utils'
import { withInfiniteScroll, connectInfiniteScroll } from '../lib/infinite_scroll_helpers'
import listMorph from '../lib/list_morph' import listMorph from '../lib/list_morph'
import { updateAllCalculatedUsdValues } from '../lib/currency.js' import { updateAllCalculatedUsdValues } from '../lib/currency.js'
import { loadTokenBalanceDropdown } from '../lib/token_balance_dropdown' import { loadTokenBalanceDropdown } from '../lib/token_balance_dropdown'
@ -23,18 +22,13 @@ export const initialState = {
transactionCount: null, transactionCount: null,
validationCount: null, validationCount: null,
transactions: [],
internalTransactions: [], internalTransactions: [],
internalTransactionsBatch: [], internalTransactionsBatch: [],
validatedBlocks: [],
beyondPageOne: null, beyondPageOne: false
nextPageUrl: $('[data-selector="transactions-list"]').length ? URI(window.location).addQuery({ type: 'JSON' }).toString() : null
} }
export const reducer = withInfiniteScroll(baseReducer) export function reducer (state = initialState, action) {
function baseReducer (state = initialState, action) {
switch (action.type) { switch (action.type) {
case 'PAGE_LOAD': case 'PAGE_LOAD':
case 'ELEMENTS_LOAD': { case 'ELEMENTS_LOAD': {
@ -85,33 +79,13 @@ function baseReducer (state = initialState, action) {
const transactionCount = (action.msg.fromAddressHash === state.addressHash) ? state.transactionCount + 1 : state.transactionCount const transactionCount = (action.msg.fromAddressHash === state.addressHash) ? state.transactionCount + 1 : state.transactionCount
if (state.beyondPageOne ||
(state.filter === 'to' && action.msg.toAddressHash !== state.addressHash) ||
(state.filter === 'from' && action.msg.fromAddressHash !== state.addressHash)) {
return Object.assign({}, state, { transactionCount }) return Object.assign({}, state, { transactionCount })
} }
return Object.assign({}, state, {
transactions: [
action.msg,
...state.transactions
],
transactionCount: transactionCount
})
}
case 'RECEIVED_UPDATED_BALANCE': { case 'RECEIVED_UPDATED_BALANCE': {
return Object.assign({}, state, { return Object.assign({}, state, {
balance: action.msg.balance balance: action.msg.balance
}) })
} }
case 'RECEIVED_NEXT_PAGE': {
return Object.assign({}, state, {
transactions: [
...state.transactions,
...action.msg.transactions
]
})
}
default: default:
return state return state
} }
@ -152,32 +126,6 @@ const elements = {
$el.empty().append(numeral(state.validationCount).format()) $el.empty().append(numeral(state.validationCount).format())
} }
}, },
'[data-selector="empty-transactions-list"]': {
render ($el, state) {
if (state.transactions.length || state.loadingNextPage || state.pagingError) {
$el.hide()
} else {
$el.show()
}
}
},
'[data-selector="transactions-list"]': {
load ($el) {
return {
transactions: $el.children().map((index, el) => ({
transactionHash: el.dataset.transactionHash,
transactionHtml: el.outerHTML
})).toArray()
}
},
render ($el, state, oldState) {
if (oldState.transactions === state.transactions) return
const container = $el[0]
const newElements = _.map(state.transactions, ({ transactionHtml }) => $(transactionHtml)[0])
return listMorph(container, newElements, { key: 'dataset.transactionHash' })
}
},
'[data-selector="internal-transactions-list"]': { '[data-selector="internal-transactions-list"]': {
load ($el) { load ($el) {
return { return {
@ -215,7 +163,6 @@ if ($addressDetailsPage.length) {
beyondPageOne: !!blockNumber beyondPageOne: !!blockNumber
}) })
connectElements({ store, elements }) connectElements({ store, elements })
$('[data-selector="transactions-list"]').length && connectInfiniteScroll(store)
const addressChannel = socket.channel(`addresses:${addressHash}`, {}) const addressChannel = socket.channel(`addresses:${addressHash}`, {})
addressChannel.join() addressChannel.join()

@ -0,0 +1,73 @@
import $ from 'jquery'
import _ from 'lodash'
import URI from 'urijs'
import humps from 'humps'
import socket from '../../socket'
import { connectElements } from '../../lib/redux_helpers.js'
import { createAsyncLoadStore } from '../../lib/async_listing_load'
export const initialState = {
addressHash: null,
channelDisconnected: false,
filter: null
}
export function reducer (state, action) {
switch (action.type) {
case 'PAGE_LOAD':
case 'ELEMENTS_LOAD': {
return Object.assign({}, state, _.omit(action, 'type'))
}
case 'CHANNEL_DISCONNECTED': {
if (state.beyondPageOne) return state
return Object.assign({}, state, { channelDisconnected: true })
}
case 'RECEIVED_NEW_TRANSACTION': {
if (state.channelDisconnected) return state
if (state.beyondPageOne ||
(state.filter === 'to' && action.msg.toAddressHash !== state.addressHash) ||
(state.filter === 'from' && action.msg.fromAddressHash !== state.addressHash)) {
return state
}
return Object.assign({}, state, { items: [ action.msg.transactionHtml, ...state.items ] })
}
default:
return state
}
}
const elements = {
'[data-selector="channel-disconnected-message"]': {
render ($el, state) {
if (state.channelDisconnected) $el.show()
}
}
}
if ($('[data-page="address-transactions"]').length) {
const store = createAsyncLoadStore(reducer, initialState, 'dataset.transactionHash')
const addressHash = $('[data-page="address-details"]')[0].dataset.pageAddressHash
const { filter, blockNumber } = humps.camelizeKeys(URI(window.location).query(true))
connectElements({ store, elements })
store.dispatch({
type: 'PAGE_LOAD',
addressHash,
filter,
beyondPageOne: !!blockNumber
})
const addressChannel = socket.channel(`addresses:${addressHash}`, {})
addressChannel.join()
addressChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' }))
addressChannel.on('transaction', (msg) => {
store.dispatch({
type: 'RECEIVED_NEW_TRANSACTION',
msg: humps.camelizeKeys(msg)
})
})
}

@ -10,7 +10,6 @@ defmodule BlockScoutWeb.AddressTransactionController do
alias BlockScoutWeb.TransactionView alias BlockScoutWeb.TransactionView
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.Chain.Hash
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Phoenix.View alias Phoenix.View
@ -48,29 +47,21 @@ defmodule BlockScoutWeb.AddressTransactionController do
conn, conn,
:index, :index,
address, address,
next_page_params Map.delete(next_page_params, "type")
) )
end end
json( transactions_json =
conn,
%{
transactions:
Enum.map(transactions, fn transaction -> Enum.map(transactions, fn transaction ->
%{
transaction_hash: Hash.to_string(transaction.hash),
transaction_html:
View.render_to_string( View.render_to_string(
TransactionView, TransactionView,
"_tile.html", "_tile.html",
current_address: address, current_address: address,
transaction: transaction transaction: transaction
) )
} end)
end),
next_page_url: next_page_url json(conn, %{items: transactions_json, next_page_path: next_page_url})
}
)
else else
:error -> :error ->
unprocessable_entity(conn) unprocessable_entity(conn)
@ -90,7 +81,8 @@ defmodule BlockScoutWeb.AddressTransactionController do
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"], filter: params["filter"],
transaction_count: transaction_count(address), transaction_count: transaction_count(address),
validation_count: validation_count(address) validation_count: validation_count(address),
current_path: current_path(conn)
) )
else else
:error -> :error ->

@ -2,13 +2,13 @@
<%= render BlockScoutWeb.AddressView, "overview.html", assigns %> <%= render BlockScoutWeb.AddressView, "overview.html", assigns %>
<section> <section data-page="address-transactions">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<%= render BlockScoutWeb.AddressView, "_tabs.html", assigns %> <%= render BlockScoutWeb.AddressView, "_tabs.html", assigns %>
</div> </div>
<div class="card-body"> <div class="card-body" data-async-listing="<%= @current_path %>">
<div data-selector="channel-disconnected-message" style="display: none;"> <div data-selector="channel-disconnected-message" style="display: none;">
<div data-selector="reload-button" class="alert alert-danger"> <div data-selector="reload-button" class="alert alert-danger">
<a href="#" class="alert-link"><%= gettext "Connection Lost, click to load newer transactions" %></a> <a href="#" class="alert-link"><%= gettext "Connection Lost, click to load newer transactions" %></a>
@ -51,20 +51,36 @@
</div> </div>
</div> </div>
<h2 class="card-title"><%= gettext "Transactions" %></h2> <h2 class="card-title"><%= gettext "Transactions" %></h2>
<span data-selector="transactions-list"> <button data-error-message class="alert alert-danger col-12 text-left" style="display: none;">
</span> <span href="#" class="alert-link"><%= gettext("Something went wrong, click to reload.") %></span>
<div data-selector="loading-next-page" class="tile tile-muted text-center mt-3"> </button>
<div data-empty-response-message style="display: none;">
<div class="tile tile-muted text-center" data-selector="empty-transactions-list">
<%= gettext "There are no transactions for this address." %>
</div>
</div>
<div data-loading-message class="tile tile-muted text-center mt-3">
<span class="loading-spinner-small mr-2"> <span class="loading-spinner-small mr-2">
<span class="loading-spinner-block-1"></span> <span class="loading-spinner-block-1"></span>
<span class="loading-spinner-block-2"></span> <span class="loading-spinner-block-2"></span>
</span> </span>
<%= gettext("Loading") %>... <%= gettext("Loading") %>...
</div> </div>
<div data-selector="paging-error-message" class="alert alert-danger text-center mt-3" style="display: none;">
<%= gettext("Error trying to fetch transactions.") %> <div data-items></div>
</div>
<div class="tile tile-muted text-center" data-selector="empty-transactions-list" style="display: none;"> <a href="#" class="button button-secondary button-small float-right mt-4" data-next-page-button style="display: none;">
<%= gettext "There are no transactions for this address." %> <%= gettext("Older") %>
</a>
<div class="button button-secondary button-small float-right mt-4" data-loading-button style="display: none;">
<span class="loading-spinner-small mr-2">
<span class="loading-spinner-block-1"></span>
<span class="loading-spinner-block-2"></span>
</span>
<%= gettext("Loading") %>...
</div> </div>
</div> </div>
</div> </div>

@ -639,6 +639,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:76 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:76
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:31 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:31
#: lib/block_scout_web/templates/address_transaction/index.html.eex:75
#: lib/block_scout_web/templates/address_validation/index.html.eex:126 #: lib/block_scout_web/templates/address_validation/index.html.eex:126
#: lib/block_scout_web/templates/block/index.html.eex:30 #: lib/block_scout_web/templates/block/index.html.eex:30
#: lib/block_scout_web/templates/block_transaction/index.html.eex:50 #: lib/block_scout_web/templates/block_transaction/index.html.eex:50
@ -851,7 +852,7 @@ msgid "There are no tokens."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:67 #: lib/block_scout_web/templates/address_transaction/index.html.eex:60
msgid "There are no transactions for this address." msgid "There are no transactions for this address."
msgstr "" msgstr ""
@ -1220,7 +1221,8 @@ msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:72 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:72
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:83 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:83
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:38 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:38
#: lib/block_scout_web/templates/address_transaction/index.html.eex:61 #: lib/block_scout_web/templates/address_transaction/index.html.eex:69
#: lib/block_scout_web/templates/address_transaction/index.html.eex:83
#: lib/block_scout_web/templates/block/index.html.eex:22 #: lib/block_scout_web/templates/block/index.html.eex:22
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:33 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:33
#: lib/block_scout_web/templates/tokens/holder/index.html.eex:37 #: lib/block_scout_web/templates/tokens/holder/index.html.eex:37
@ -1251,11 +1253,6 @@ msgstr ""
msgid "Show Raw Input" msgid "Show Raw Input"
msgstr "" msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:64
msgid "Error trying to fetch transactions."
msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/block_transaction/404.html.eex:7 #: lib/block_scout_web/templates/block_transaction/404.html.eex:7
msgid "Block Details" msgid "Block Details"
@ -1419,6 +1416,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:60 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:60
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:26 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:26
#: lib/block_scout_web/templates/address_transaction/index.html.eex:55
#: lib/block_scout_web/templates/address_validation/index.html.eex:121 #: lib/block_scout_web/templates/address_validation/index.html.eex:121
#: lib/block_scout_web/templates/tokens/holder/index.html.eex:23 #: lib/block_scout_web/templates/tokens/holder/index.html.eex:23
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:21 #: lib/block_scout_web/templates/tokens/transfer/index.html.eex:21

@ -639,6 +639,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:76 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:76
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:31 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:31
#: lib/block_scout_web/templates/address_transaction/index.html.eex:75
#: lib/block_scout_web/templates/address_validation/index.html.eex:126 #: lib/block_scout_web/templates/address_validation/index.html.eex:126
#: lib/block_scout_web/templates/block/index.html.eex:30 #: lib/block_scout_web/templates/block/index.html.eex:30
#: lib/block_scout_web/templates/block_transaction/index.html.eex:50 #: lib/block_scout_web/templates/block_transaction/index.html.eex:50
@ -851,7 +852,7 @@ msgid "There are no tokens."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:67 #: lib/block_scout_web/templates/address_transaction/index.html.eex:60
msgid "There are no transactions for this address." msgid "There are no transactions for this address."
msgstr "" msgstr ""
@ -1220,7 +1221,8 @@ msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:72 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:72
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:83 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:83
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:38 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:38
#: lib/block_scout_web/templates/address_transaction/index.html.eex:61 #: lib/block_scout_web/templates/address_transaction/index.html.eex:69
#: lib/block_scout_web/templates/address_transaction/index.html.eex:83
#: lib/block_scout_web/templates/block/index.html.eex:22 #: lib/block_scout_web/templates/block/index.html.eex:22
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:33 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:33
#: lib/block_scout_web/templates/tokens/holder/index.html.eex:37 #: lib/block_scout_web/templates/tokens/holder/index.html.eex:37
@ -1251,11 +1253,6 @@ msgstr ""
msgid "Show Raw Input" msgid "Show Raw Input"
msgstr "" msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:64
msgid "Error trying to fetch transactions."
msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/block_transaction/404.html.eex:7 #: lib/block_scout_web/templates/block_transaction/404.html.eex:7
msgid "Block Details" msgid "Block Details"
@ -1419,6 +1416,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:60 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:60
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:26 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:26
#: lib/block_scout_web/templates/address_transaction/index.html.eex:55
#: lib/block_scout_web/templates/address_validation/index.html.eex:121 #: lib/block_scout_web/templates/address_validation/index.html.eex:121
#: lib/block_scout_web/templates/tokens/holder/index.html.eex:23 #: lib/block_scout_web/templates/tokens/holder/index.html.eex:23
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:21 #: lib/block_scout_web/templates/tokens/transfer/index.html.eex:21

@ -34,15 +34,14 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
|> insert(to_address: address) |> insert(to_address: address)
|> with_block(block) |> with_block(block)
conn = get(conn, address_transaction_path(conn, :index, address), %{"type" => "JSON"}) conn = get(conn, address_transaction_path(conn, :index, address, %{"type" => "JSON"}))
{:ok, %{"transactions" => transactions}} = conn.resp_body |> Poison.decode()
actual_transaction_hashes = Enum.map(transactions, & &1["transaction_hash"]) transaction_tiles = json_response(conn, 200)["items"]
transaction_hashes = Enum.map([to_transaction.hash, from_transaction.hash], &to_string(&1))
assert json_response(conn, 200) assert Enum.all?(transaction_hashes, fn transaction_hash ->
assert Enum.member?(actual_transaction_hashes, to_string(from_transaction.hash)) Enum.any?(transaction_tiles, &String.contains?(&1, transaction_hash))
assert Enum.member?(actual_transaction_hashes, to_string(to_transaction.hash)) end)
end end
test "includes USD exchange rate value for address in assigns", %{conn: conn} do test "includes USD exchange rate value for address in assigns", %{conn: conn} do
@ -60,7 +59,7 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
50 50
|> insert_list(:transaction, from_address: address) |> insert_list(:transaction, from_address: address)
|> with_block() |> with_block()
|> Enum.map(&to_string(&1.hash)) |> Enum.map(& &1.hash)
%Transaction{block_number: block_number, index: index} = %Transaction{block_number: block_number, index: index} =
:transaction :transaction
@ -69,19 +68,16 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
conn = conn =
get(conn, address_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash), %{ get(conn, address_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash), %{
"type" => "JSON",
"block_number" => Integer.to_string(block_number), "block_number" => Integer.to_string(block_number),
"index" => Integer.to_string(index) "index" => Integer.to_string(index),
"type" => "JSON"
}) })
{:ok, %{"transactions" => transactions}} = conn.resp_body |> Poison.decode() transaction_tiles = json_response(conn, 200)["items"]
actual_hashes = assert Enum.all?(second_page_hashes, fn address_hash ->
transactions Enum.any?(transaction_tiles, &String.contains?(&1, to_string(address_hash)))
|> Enum.map(& &1["transaction_hash"]) end)
|> Enum.reverse()
assert second_page_hashes == actual_hashes
end end
test "next_page_params exist if not on last page", %{conn: conn} do test "next_page_params exist if not on last page", %{conn: conn} do
@ -92,18 +88,9 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
|> insert_list(:transaction, from_address: address) |> insert_list(:transaction, from_address: address)
|> with_block(block) |> with_block(block)
conn = get(conn, address_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash), %{"type" => "JSON"}) conn = get(conn, address_transaction_path(conn, :index, address.hash, %{"type" => "JSON"}))
{:ok, %{"next_page_url" => actual_next_page_url}} = conn.resp_body |> Poison.decode()
expected_next_page_url = assert json_response(conn, 200)["next_page_path"]
address_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash, %{
"block_number" => number,
"index" => 10,
"type" => "JSON"
})
assert expected_next_page_url == actual_next_page_url
end end
test "next_page_params are empty if on last page", %{conn: conn} do test "next_page_params are empty if on last page", %{conn: conn} do
@ -113,11 +100,9 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
|> insert(from_address: address) |> insert(from_address: address)
|> with_block() |> with_block()
conn = get(conn, address_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash), %{"type" => "JSON"}) conn = get(conn, address_transaction_path(conn, :index, address.hash, %{"type" => "JSON"}))
{:ok, %{"next_page_url" => next_page_url}} = conn.resp_body |> Poison.decode() refute json_response(conn, 200)["next_page_path"]
refute next_page_url
end end
test "returns parent transaction for a contract address", %{conn: conn} do test "returns parent transaction for a contract address", %{conn: conn} do
@ -140,11 +125,11 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
conn = get(conn, address_transaction_path(conn, :index, address), %{"type" => "JSON"}) conn = get(conn, address_transaction_path(conn, :index, address), %{"type" => "JSON"})
{:ok, %{"transactions" => transactions}} = conn.resp_body |> Poison.decode() transaction_tiles = json_response(conn, 200)["items"]
transaction_hashes = Enum.map(transactions, & &1["transaction_hash"])
assert [to_string(transaction.hash)] == transaction_hashes assert Enum.all?([transaction.hash], fn transaction_hash ->
Enum.any?(transaction_tiles, &String.contains?(&1, to_string(transaction_hash)))
end)
end end
end end
end end

Loading…
Cancel
Save