diff --git a/conda/js/src/components/toolchain/ToolchainEditor.spec.jsx b/conda/js/src/components/toolchain/ToolchainEditor.spec.jsx
index 3c82fbc47937c8d6aea66a7523f917b36cf73e46..0abe32af92e5bda34c3eef2e51d41f6bf3493e73 100644
--- a/conda/js/src/components/toolchain/ToolchainEditor.spec.jsx
+++ b/conda/js/src/components/toolchain/ToolchainEditor.spec.jsx
@@ -158,7 +158,7 @@ const getIrisTc = (color1: string = '#008000', color2: string = '#FF0000') => {
 
 chai.use(deepEqualInAnyOrder);
 
-describe.only('<ToolchainEditor />', function() {
+describe('<ToolchainEditor />', function() {
 	// these tests might take a long time, comparatively
 	this.timeout(10000);
 
diff --git a/conda/js/src/components/toolchain/ToolchainModal.jsx b/conda/js/src/components/toolchain/ToolchainModal.jsx
index 0828e6a4db154c98ab43e02151dff63dfcbf28a5..0d6bb84e0e630bd0aa55b8db79ff3b011dd3c4e1 100644
--- a/conda/js/src/components/toolchain/ToolchainModal.jsx
+++ b/conda/js/src/components/toolchain/ToolchainModal.jsx
@@ -30,16 +30,19 @@ import {
 import CacheInput from '../CacheInput.jsx';
 import DeleteInputBtn from '../DeleteInputBtn.jsx';
 import { generateNewKey } from '@helpers';
+import type { BlockType } from '@helpers/toolchainTypes';
 
 type Props = {
-	// block data
-	data: any,
-	// func to close modal
-	toggle: () => any,
 	// is the modal active?
 	active: boolean,
+	// block data
+	data: BlockType,
 	// name of all blocks
 	blockNames: string[],
+	// possible channels the block can be sync'd to (an obj w keys as channel names & vals as colours)
+	possibleChannels: { [string]: string },
+	// func to close modal
+	toggle: () => any,
 	// change the block name
 	updateBlockName: (newName: string) => any,
 	// change the name of an input or output
@@ -50,8 +53,6 @@ type Props = {
 	deleteBlockIO: (ioType: 'input' | 'output', ioName: string) => any,
 	// delete the block
 	deleteBlock: () => any,
-	// possible channels the block can be sync'd to (an obj w keys as channel names & vals as colours)
-	possibleChannels: any,
 	// update sync'd channel
 	updateBlockChannel: (channel: string) => any,
 };
@@ -112,11 +113,16 @@ class ToolchainModal extends React.Component<Props, State> {
 									this.props.updateBlockName(e.target.value);
 								}}
 								validateFunc={(str) => {
-									return (
-										str === data.name ||
-										!this.props.blockNames.includes(str) ||
-										<span>This name is already taken by an existing block</span>
-									);
+									if(str === data.name){
+										return true;
+									}
+									if(this.props.blockNames.includes(str)){
+										return <span>This name is already taken by an existing block</span>;
+									}
+									if(str.includes('-')){
+										return <span>{`Cannot include the dash ("-") character`}</span>;
+									}
+									return true;
 								}}
 							/>
 						</FormGroup>
diff --git a/conda/js/src/components/toolchain/ToolchainModal.spec.jsx b/conda/js/src/components/toolchain/ToolchainModal.spec.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..7849ab9d4ad3ff0b7d38f64fe16049d0813ef351
--- /dev/null
+++ b/conda/js/src/components/toolchain/ToolchainModal.spec.jsx
@@ -0,0 +1,122 @@
+// @flow
+import React from 'react';
+import { expect } from 'chai';
+import { mount } from 'enzyme';
+import sinon from 'sinon';
+import { spies } from '@test';
+
+import C from './ToolchainModal.jsx';
+
+// sleep for a bit, to wait for async things
+const sleep = (ms) => {
+	return new Promise(resolve => setTimeout(resolve, ms));
+};
+
+describe.only('<ToolchainModal />', () => {
+	let wrapper;
+
+	afterEach(() => {
+		if(wrapper && wrapper.unmount)
+			wrapper.unmount();
+	});
+
+	const testBlockData = {
+		name: 'block1',
+		inputs: [
+			'input1',
+		],
+		outputs: [
+			'output1',
+		],
+		synchronized_channel: 'dataset1',
+	};
+
+	const testChannels = { 'dataset1': '#880000' };
+
+	const testBlockNames = ['block1'];
+
+	it('accepts the test data with the right props', () => {
+		wrapper = mount(
+			<C
+				active={true}
+				data={testBlockData}
+				blockNames={testBlockNames}
+				possibleChannels={testChannels}
+				toggle={() => {}}
+				updateBlockName={() => {}}
+				updateBlockChannel={() => {}}
+				updateBlockIOName={() => {}}
+				addBlockIO={() => {}}
+				deleteBlockIO={() => {}}
+				deleteBlock={() => {}}
+			/>
+		);
+		expect(wrapper).to.have.props([
+			'active',
+			'data',
+			'blockNames',
+			'possibleChannels',
+			'toggle',
+			'updateBlockName',
+			'updateBlockChannel',
+			'updateBlockIOName',
+			'addBlockIO',
+			'deleteBlockIO',
+			'deleteBlock',
+		]);
+	});
+
+	it('lets you change the name to another valid name', async () => {
+		const newBlockName = 'block2';
+		const _updateBlockName = (str: string) => {
+			expect(str).to.equal(newBlockName);
+		};
+		wrapper = mount(
+			<C
+				active={true}
+				data={testBlockData}
+				blockNames={testBlockNames}
+				possibleChannels={testChannels}
+				toggle={() => {}}
+				updateBlockName={_updateBlockName}
+				updateBlockChannel={() => {}}
+				updateBlockIOName={() => {}}
+				addBlockIO={() => {}}
+				deleteBlockIO={() => {}}
+				deleteBlock={() => {}}
+			/>
+		);
+		wrapper.find('input#tcModalInitFocus').prop('onChange')( { target: { value: newBlockName }});
+		wrapper.update();
+		await sleep(300);
+		wrapper.update();
+		expect(wrapper.exists('.input-group-append .text-danger')).to.equal(false);
+	});
+
+	it('doesnt let you change the name to a valid name with a dash ("-") in it', async () => {
+		const newBlockName = 'block-2';
+		const _updateBlockName = (str: string) => {
+			expect(str).to.equal(newBlockName);
+		};
+		wrapper = mount(
+			<C
+				active={true}
+				data={testBlockData}
+				blockNames={testBlockNames}
+				possibleChannels={testChannels}
+				toggle={() => {}}
+				updateBlockName={_updateBlockName}
+				updateBlockChannel={() => {}}
+				updateBlockIOName={() => {}}
+				addBlockIO={() => {}}
+				deleteBlockIO={() => {}}
+				deleteBlock={() => {}}
+			/>
+		);
+		wrapper.find('input#tcModalInitFocus').prop('onChange')( { target: { value: newBlockName }});
+		wrapper.update();
+		await sleep(300);
+		wrapper.update();
+		expect(wrapper.exists('.input-group-append .text-danger')).to.equal(true);
+	});
+});